summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Swanson <charlie.swanson@mongodb.com>2021-06-25 07:59:45 -0400
committerCharlie Swanson <charlie.swanson@mongodb.com>2021-06-29 08:33:14 -0400
commitea3c687d439065d00c7897bbe1d50a378edacb11 (patch)
treece17b90ae2bd5a221750d1b00d2476c5e3514c88
parent751eb739c00c463b54823e7ab6da74c40172365f (diff)
downloadmongo-ea3c687d439065d00c7897bbe1d50a378edacb11.tar.gz
SERVER-58076 Exclude new 5.0 language features from stable API
(cherry picked from commit 7558a7a36cbfcc0af39b0f0bf07861f162c590d2)
-rw-r--r--jstests/core/api_version_new_50_language_features.js78
-rw-r--r--src/mongo/db/SConscript4
-rw-r--r--src/mongo/db/pipeline/SConscript3
-rw-r--r--src/mongo/db/pipeline/accumulator_avg.cpp2
-rw-r--r--src/mongo/db/pipeline/accumulator_merge_objects.cpp2
-rw-r--r--src/mongo/db/pipeline/accumulator_min_max.cpp4
-rw-r--r--src/mongo/db/pipeline/accumulator_std_dev.cpp4
-rw-r--r--src/mongo/db/pipeline/accumulator_sum.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source.h63
-rw-r--r--src/mongo/db/pipeline/document_source_add_fields.cpp4
-rw-r--r--src/mongo/db/pipeline/document_source_bucket.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_bucket_auto.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_change_stream.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_coll_stats.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_count.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_current_op.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_facet.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_geo_near.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_graph_lookup.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_group.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_index_stats.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_internal_inhibit_optimization.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_internal_split_pipeline.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp4
-rw-r--r--src/mongo/db/pipeline/document_source_limit.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_list_local_sessions.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_list_sessions.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_lookup.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_match.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_merge.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_operation_metrics.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_out.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_plan_cache_stats.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_project.cpp4
-rw-r--r--src/mongo/db/pipeline/document_source_redact.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_replace_root.cpp4
-rw-r--r--src/mongo/db/pipeline/document_source_sample.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_set_window_fields.cpp4
-rw-r--r--src/mongo/db/pipeline/document_source_skip.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_sort.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_sort_by_count.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_union_with.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_unwind.cpp2
-rw-r--r--src/mongo/db/pipeline/expression.cpp242
-rw-r--r--src/mongo/db/pipeline/expression.h85
-rw-r--r--src/mongo/db/pipeline/expression_function.cpp2
-rw-r--r--src/mongo/db/pipeline/expression_js_emit.cpp2
-rw-r--r--src/mongo/db/pipeline/expression_test_api_version.cpp5
-rw-r--r--src/mongo/db/pipeline/expression_trigonometric.cpp30
-rw-r--r--src/mongo/db/pipeline/lite_parsed_document_source.h27
-rw-r--r--src/mongo/db/pipeline/lite_parsed_pipeline.cpp57
-rw-r--r--src/mongo/db/query/SConscript11
-rw-r--r--src/mongo/db/query/allowed_contexts.cpp91
-rw-r--r--src/mongo/db/query/allowed_contexts.h77
-rw-r--r--src/mongo/s/query/document_source_merge_cursors.cpp2
56 files changed, 559 insertions, 314 deletions
diff --git a/jstests/core/api_version_new_50_language_features.js b/jstests/core/api_version_new_50_language_features.js
new file mode 100644
index 00000000000..c11abd84885
--- /dev/null
+++ b/jstests/core/api_version_new_50_language_features.js
@@ -0,0 +1,78 @@
+/**
+ * Tests that language features introduced in version 4.9 or 5.0 are not included in API Version 1
+ * yet. This test should be updated or removed in a future release when we have more confidence that
+ * the behavior and syntax is stable.
+ *
+ * @tags: [
+ * requires_fcv_50,
+ * uses_api_parameters,
+ * ]
+ */
+
+(function() {
+"use strict";
+
+const collName = "api_version_new_50_language_features";
+const coll = db[collName];
+coll.drop();
+assert.commandWorked(coll.insert({a: 1, date: new ISODate()}));
+
+const unstablePipelines = [
+ [{
+ $setWindowFields: {
+ sortBy: {_id: 1},
+ output: {runningCount: {$sum: 1, window: {documents: ["unbounded", "current"]}}}
+ }
+ }],
+ [{$set: {x: {$dateTrunc: {date: "$date", unit: "second", binSize: 5}}}}],
+ [{$set: {x: {$dateAdd: {startDate: "$date", unit: "day", amount: 1}}}}],
+ [{$set: {x: {$dateSubtract: {startDate: "$date", unit: "day", amount: 1}}}}],
+ [{$set: {x: {$getField: {input: "$$ROOT", field: "x"}}}}],
+ [{$set: {x: {$setField: {input: "$$ROOT", field: "x", value: "foo"}}}}],
+];
+
+function assertAggregateFailsWithAPIStrict(pipeline) {
+ assert.commandFailedWithCode(db.runCommand({
+ aggregate: collName,
+ pipeline: pipeline,
+ cursor: {},
+ apiStrict: true,
+ apiVersion: "1"
+ }),
+ ErrorCodes.APIStrictError,
+ pipeline);
+}
+
+for (let pipeline of unstablePipelines) {
+ // Assert error thrown when running a pipeline with stages not in API Version 1.
+ assertAggregateFailsWithAPIStrict(pipeline);
+
+ // Assert error thrown when creating a view on a pipeline with stages not in API Version 1.
+ assert.commandFailedWithCode(db.runCommand({
+ create: 'new_50_feature_view',
+ viewOn: collName,
+ pipeline: pipeline,
+ apiStrict: true,
+ apiVersion: "1"
+ }),
+ ErrorCodes.APIStrictError,
+ pipeline);
+
+ // Assert error is not thrown when running without apiStrict=true.
+ assert.commandWorked(db.runCommand({
+ aggregate: coll.getName(),
+ pipeline: pipeline,
+ apiVersion: "1",
+ cursor: {},
+ }));
+}
+
+// Creating a collection with the unstable validator is not allowed with apiStrict:true.
+assert.commandFailedWithCode(db.runCommand({
+ create: 'new_50_features_validator',
+ validator: {$expr: {$eq: [{$getField: {input: "$$ROOT", field: "dotted.path"}}, 2]}},
+ apiVersion: "1",
+ apiStrict: true
+}),
+ ErrorCodes.APIStrictError);
+})();
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 6060fad1faa..64d8c5599f1 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -582,7 +582,7 @@ env.Library(
'$BUILD_DIR/mongo/db/auth/authprivilege',
'$BUILD_DIR/mongo/db/catalog/collection_options_idl',
'$BUILD_DIR/mongo/db/commands/create_command',
- '$BUILD_DIR/mongo/db/query/explain_options',
+ '$BUILD_DIR/mongo/db/query/common_query_enums_and_helpers',
'$BUILD_DIR/mongo/idl/idl_parser',
'$BUILD_DIR/mongo/rpc/command_status',
'$BUILD_DIR/mongo/rpc/rewrite_state_change_errors',
@@ -2377,7 +2377,7 @@ if wiredtiger:
'$BUILD_DIR/mongo/db/catalog/import_collection_oplog_entry',
'$BUILD_DIR/mongo/db/catalog/index_build_entry_idl',
'$BUILD_DIR/mongo/db/mongohasher',
- '$BUILD_DIR/mongo/db/query/explain_options',
+ '$BUILD_DIR/mongo/db/query/common_query_enums_and_helpers',
'$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/storage/wiredtiger/storage_wiredtiger',
'$BUILD_DIR/mongo/executor/async_timer_mock',
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index 57e731d200b..b59eeedfdc2 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -48,7 +48,7 @@ env.Library(
'$BUILD_DIR/mongo/db/exec/document_value/document_value',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/query/command_request_response',
- '$BUILD_DIR/mongo/db/query/explain_options',
+ '$BUILD_DIR/mongo/db/query/common_query_enums_and_helpers',
'$BUILD_DIR/mongo/db/query/query_request',
'$BUILD_DIR/mongo/db/repl/read_concern_args',
'$BUILD_DIR/mongo/db/storage/storage_options',
@@ -197,6 +197,7 @@ env.Library(
'lite_parsed_pipeline.cpp',
],
LIBDEPS=[
+ '$BUILD_DIR/mongo/db/query/common_query_enums_and_helpers',
'$BUILD_DIR/mongo/db/stats/counters',
'aggregation_request_helper',
]
diff --git a/src/mongo/db/pipeline/accumulator_avg.cpp b/src/mongo/db/pipeline/accumulator_avg.cpp
index 201ee31c342..b141b091074 100644
--- a/src/mongo/db/pipeline/accumulator_avg.cpp
+++ b/src/mongo/db/pipeline/accumulator_avg.cpp
@@ -45,7 +45,7 @@ namespace mongo {
using boost::intrusive_ptr;
REGISTER_ACCUMULATOR(avg, genericParseSingleExpressionAccumulator<AccumulatorAvg>);
-REGISTER_EXPRESSION(avg, ExpressionFromAccumulator<AccumulatorAvg>::parse);
+REGISTER_STABLE_EXPRESSION(avg, ExpressionFromAccumulator<AccumulatorAvg>::parse);
REGISTER_REMOVABLE_WINDOW_FUNCTION(avg, AccumulatorAvg, WindowFunctionAvg);
const char* AccumulatorAvg::getOpName() const {
diff --git a/src/mongo/db/pipeline/accumulator_merge_objects.cpp b/src/mongo/db/pipeline/accumulator_merge_objects.cpp
index 8804a8a0f05..72943b74a70 100644
--- a/src/mongo/db/pipeline/accumulator_merge_objects.cpp
+++ b/src/mongo/db/pipeline/accumulator_merge_objects.cpp
@@ -43,7 +43,7 @@ using boost::intrusive_ptr;
REGISTER_ACCUMULATOR(mergeObjects,
genericParseSingleExpressionAccumulator<AccumulatorMergeObjects>);
-REGISTER_EXPRESSION(mergeObjects, ExpressionFromAccumulator<AccumulatorMergeObjects>::parse);
+REGISTER_STABLE_EXPRESSION(mergeObjects, ExpressionFromAccumulator<AccumulatorMergeObjects>::parse);
const char* AccumulatorMergeObjects::getOpName() const {
return "$mergeObjects";
diff --git a/src/mongo/db/pipeline/accumulator_min_max.cpp b/src/mongo/db/pipeline/accumulator_min_max.cpp
index d0d3758487d..b6d7c3db74d 100644
--- a/src/mongo/db/pipeline/accumulator_min_max.cpp
+++ b/src/mongo/db/pipeline/accumulator_min_max.cpp
@@ -43,8 +43,8 @@ using boost::intrusive_ptr;
REGISTER_ACCUMULATOR(max, genericParseSingleExpressionAccumulator<AccumulatorMax>);
REGISTER_ACCUMULATOR(min, genericParseSingleExpressionAccumulator<AccumulatorMin>);
-REGISTER_EXPRESSION(max, ExpressionFromAccumulator<AccumulatorMax>::parse);
-REGISTER_EXPRESSION(min, ExpressionFromAccumulator<AccumulatorMin>::parse);
+REGISTER_STABLE_EXPRESSION(max, ExpressionFromAccumulator<AccumulatorMax>::parse);
+REGISTER_STABLE_EXPRESSION(min, ExpressionFromAccumulator<AccumulatorMin>::parse);
REGISTER_REMOVABLE_WINDOW_FUNCTION(max, AccumulatorMax, WindowFunctionMax);
REGISTER_REMOVABLE_WINDOW_FUNCTION(min, AccumulatorMin, WindowFunctionMin);
diff --git a/src/mongo/db/pipeline/accumulator_std_dev.cpp b/src/mongo/db/pipeline/accumulator_std_dev.cpp
index e2208d92ff0..dd64ffb8750 100644
--- a/src/mongo/db/pipeline/accumulator_std_dev.cpp
+++ b/src/mongo/db/pipeline/accumulator_std_dev.cpp
@@ -44,8 +44,8 @@ using boost::intrusive_ptr;
REGISTER_ACCUMULATOR(stdDevPop, genericParseSingleExpressionAccumulator<AccumulatorStdDevPop>);
REGISTER_ACCUMULATOR(stdDevSamp, genericParseSingleExpressionAccumulator<AccumulatorStdDevSamp>);
-REGISTER_EXPRESSION(stdDevPop, ExpressionFromAccumulator<AccumulatorStdDevPop>::parse);
-REGISTER_EXPRESSION(stdDevSamp, ExpressionFromAccumulator<AccumulatorStdDevSamp>::parse);
+REGISTER_STABLE_EXPRESSION(stdDevPop, ExpressionFromAccumulator<AccumulatorStdDevPop>::parse);
+REGISTER_STABLE_EXPRESSION(stdDevSamp, ExpressionFromAccumulator<AccumulatorStdDevSamp>::parse);
REGISTER_REMOVABLE_WINDOW_FUNCTION(stdDevPop, AccumulatorStdDevPop, WindowFunctionStdDevPop);
REGISTER_REMOVABLE_WINDOW_FUNCTION(stdDevSamp, AccumulatorStdDevSamp, WindowFunctionStdDevSamp);
diff --git a/src/mongo/db/pipeline/accumulator_sum.cpp b/src/mongo/db/pipeline/accumulator_sum.cpp
index c0033f281cc..587a1b86e88 100644
--- a/src/mongo/db/pipeline/accumulator_sum.cpp
+++ b/src/mongo/db/pipeline/accumulator_sum.cpp
@@ -47,7 +47,7 @@ namespace mongo {
using boost::intrusive_ptr;
REGISTER_ACCUMULATOR(sum, genericParseSingleExpressionAccumulator<AccumulatorSum>);
-REGISTER_EXPRESSION(sum, ExpressionFromAccumulator<AccumulatorSum>::parse);
+REGISTER_STABLE_EXPRESSION(sum, ExpressionFromAccumulator<AccumulatorSum>::parse);
REGISTER_REMOVABLE_WINDOW_FUNCTION(sum, AccumulatorSum, WindowFunctionSum);
REGISTER_ACCUMULATOR_WITH_MIN_VERSION(
count, parseCountAccumulator, ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h
index 89e4c9d6905..d163c88761e 100644
--- a/src/mongo/db/pipeline/document_source.h
+++ b/src/mongo/db/pipeline/document_source.h
@@ -56,6 +56,7 @@
#include "mongo/db/pipeline/lite_parsed_document_source.h"
#include "mongo/db/pipeline/pipeline.h"
#include "mongo/db/pipeline/stage_constraints.h"
+#include "mongo/db/query/allowed_contexts.h"
#include "mongo/db/query/explain_options.h"
#include "mongo/util/intrusive_counter.h"
@@ -86,13 +87,13 @@ class Document;
* LiteParsedDocumentSourceDefault::parse,
* DocumentSourceFoo::createFromBson);
*/
-#define REGISTER_DOCUMENT_SOURCE(key, liteParser, fullParser, allowedWithApiStrict) \
- REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
- liteParser, \
- fullParser, \
- allowedWithApiStrict, \
- LiteParsedDocumentSource::AllowedWithClientType::kAny, \
- boost::none, \
+#define REGISTER_DOCUMENT_SOURCE(key, liteParser, fullParser, allowedWithApiStrict) \
+ REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
+ liteParser, \
+ fullParser, \
+ allowedWithApiStrict, \
+ AllowedWithClientType::kAny, \
+ boost::none, \
true)
/**
@@ -100,28 +101,27 @@ class Document;
* We store minVersion in the parserMap, so that changing FCV at runtime correctly enables/disables
* the parser.
*/
-#define REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION( \
- key, liteParser, fullParser, allowedWithApiStrict, minVersion) \
- REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
- liteParser, \
- fullParser, \
- allowedWithApiStrict, \
- LiteParsedDocumentSource::AllowedWithClientType::kAny, \
- minVersion, \
+#define REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION( \
+ key, liteParser, fullParser, allowedWithApiStrict, minVersion) \
+ REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
+ liteParser, \
+ fullParser, \
+ allowedWithApiStrict, \
+ AllowedWithClientType::kAny, \
+ minVersion, \
true)
/**
* Registers a DocumentSource which cannot be exposed to the users.
*/
#define REGISTER_INTERNAL_DOCUMENT_SOURCE(key, liteParser, fullParser, condition) \
- REGISTER_DOCUMENT_SOURCE_CONDITIONALLY( \
- key, \
- liteParser, \
- fullParser, \
- LiteParsedDocumentSource::AllowedWithApiStrict::kInternal, \
- LiteParsedDocumentSource::AllowedWithClientType::kInternal, \
- boost::none, \
- condition)
+ REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
+ liteParser, \
+ fullParser, \
+ AllowedWithApiStrict::kInternal, \
+ AllowedWithClientType::kInternal, \
+ boost::none, \
+ condition)
/**
* Like REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION, except you can also specify a condition,
@@ -149,15 +149,14 @@ class Document;
/**
* Like REGISTER_DOCUMENT_SOURCE, except the parser is only enabled when test-commands are enabled.
*/
-#define REGISTER_TEST_DOCUMENT_SOURCE(key, liteParser, fullParser) \
- REGISTER_DOCUMENT_SOURCE_CONDITIONALLY( \
- key, \
- liteParser, \
- fullParser, \
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1, \
- LiteParsedDocumentSource::AllowedWithClientType::kAny, \
- boost::none, \
- ::mongo::getTestCommandsEnabled())
+#define REGISTER_TEST_DOCUMENT_SOURCE(key, liteParser, fullParser) \
+ REGISTER_DOCUMENT_SOURCE_CONDITIONALLY(key, \
+ liteParser, \
+ fullParser, \
+ AllowedWithApiStrict::kNeverInVersion1, \
+ AllowedWithClientType::kAny, \
+ boost::none, \
+ ::mongo::getTestCommandsEnabled())
class DocumentSource : public RefCountable {
public:
diff --git a/src/mongo/db/pipeline/document_source_add_fields.cpp b/src/mongo/db/pipeline/document_source_add_fields.cpp
index ec245402c2a..448715a96ea 100644
--- a/src/mongo/db/pipeline/document_source_add_fields.cpp
+++ b/src/mongo/db/pipeline/document_source_add_fields.cpp
@@ -43,11 +43,11 @@ using boost::intrusive_ptr;
REGISTER_DOCUMENT_SOURCE(addFields,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceAddFields::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
REGISTER_DOCUMENT_SOURCE(set,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceAddFields::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
intrusive_ptr<DocumentSource> DocumentSourceAddFields::create(
BSONObj addFieldsSpec,
diff --git a/src/mongo/db/pipeline/document_source_bucket.cpp b/src/mongo/db/pipeline/document_source_bucket.cpp
index 5fe098ae418..4de8daee491 100644
--- a/src/mongo/db/pipeline/document_source_bucket.cpp
+++ b/src/mongo/db/pipeline/document_source_bucket.cpp
@@ -43,7 +43,7 @@ using std::vector;
REGISTER_DOCUMENT_SOURCE(bucket,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceBucket::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
namespace {
intrusive_ptr<ExpressionConstant> getExpressionConstant(ExpressionContext* const expCtx,
diff --git a/src/mongo/db/pipeline/document_source_bucket_auto.cpp b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
index 1ffac313f28..87b619d40ec 100644
--- a/src/mongo/db/pipeline/document_source_bucket_auto.cpp
+++ b/src/mongo/db/pipeline/document_source_bucket_auto.cpp
@@ -45,7 +45,7 @@ using std::vector;
REGISTER_DOCUMENT_SOURCE(bucketAuto,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceBucketAuto::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
namespace {
diff --git a/src/mongo/db/pipeline/document_source_change_stream.cpp b/src/mongo/db/pipeline/document_source_change_stream.cpp
index a1543b79dfd..bb95cfba0e0 100644
--- a/src/mongo/db/pipeline/document_source_change_stream.cpp
+++ b/src/mongo/db/pipeline/document_source_change_stream.cpp
@@ -72,7 +72,7 @@ using std::vector;
REGISTER_DOCUMENT_SOURCE(changeStream,
DocumentSourceChangeStream::LiteParsed::parse,
DocumentSourceChangeStream::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
constexpr StringData DocumentSourceChangeStream::kDocumentKeyField;
constexpr StringData DocumentSourceChangeStream::kFullDocumentBeforeChangeField;
diff --git a/src/mongo/db/pipeline/document_source_coll_stats.cpp b/src/mongo/db/pipeline/document_source_coll_stats.cpp
index e7c9681d880..6dc42ee7659 100644
--- a/src/mongo/db/pipeline/document_source_coll_stats.cpp
+++ b/src/mongo/db/pipeline/document_source_coll_stats.cpp
@@ -44,7 +44,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(collStats,
DocumentSourceCollStats::LiteParsed::parse,
DocumentSourceCollStats::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kSometimes);
+ AllowedWithApiStrict::kSometimes);
void DocumentSourceCollStats::LiteParsed::assertPermittedInAPIVersion(
const APIParameters& apiParameters) const {
diff --git a/src/mongo/db/pipeline/document_source_count.cpp b/src/mongo/db/pipeline/document_source_count.cpp
index 988bf414da3..bef22eef178 100644
--- a/src/mongo/db/pipeline/document_source_count.cpp
+++ b/src/mongo/db/pipeline/document_source_count.cpp
@@ -46,7 +46,7 @@ using std::string;
REGISTER_DOCUMENT_SOURCE(count,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceCount::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
list<intrusive_ptr<DocumentSource>> DocumentSourceCount::createFromBson(
BSONElement elem, const intrusive_ptr<ExpressionContext>& pExpCtx) {
diff --git a/src/mongo/db/pipeline/document_source_current_op.cpp b/src/mongo/db/pipeline/document_source_current_op.cpp
index da1dda80226..7b453935dee 100644
--- a/src/mongo/db/pipeline/document_source_current_op.cpp
+++ b/src/mongo/db/pipeline/document_source_current_op.cpp
@@ -55,7 +55,7 @@ using boost::intrusive_ptr;
REGISTER_DOCUMENT_SOURCE(currentOp,
DocumentSourceCurrentOp::LiteParsed::parse,
DocumentSourceCurrentOp::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
constexpr StringData DocumentSourceCurrentOp::kStageName;
diff --git a/src/mongo/db/pipeline/document_source_facet.cpp b/src/mongo/db/pipeline/document_source_facet.cpp
index 2cee70a250c..4d8da6de141 100644
--- a/src/mongo/db/pipeline/document_source_facet.cpp
+++ b/src/mongo/db/pipeline/document_source_facet.cpp
@@ -124,7 +124,7 @@ std::unique_ptr<DocumentSourceFacet::LiteParsed> DocumentSourceFacet::LiteParsed
REGISTER_DOCUMENT_SOURCE(facet,
DocumentSourceFacet::LiteParsed::parse,
DocumentSourceFacet::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
intrusive_ptr<DocumentSourceFacet> DocumentSourceFacet::create(
std::vector<FacetPipeline> facetPipelines,
diff --git a/src/mongo/db/pipeline/document_source_geo_near.cpp b/src/mongo/db/pipeline/document_source_geo_near.cpp
index a5b49788551..e10b9e59b50 100644
--- a/src/mongo/db/pipeline/document_source_geo_near.cpp
+++ b/src/mongo/db/pipeline/document_source_geo_near.cpp
@@ -47,7 +47,7 @@ constexpr StringData DocumentSourceGeoNear::kKeyFieldName;
REGISTER_DOCUMENT_SOURCE(geoNear,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceGeoNear::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
Value DocumentSourceGeoNear::serialize(boost::optional<ExplainOptions::Verbosity> explain) const {
MutableDocument result;
diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
index eca4b8b8211..c6550aef5f6 100644
--- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp
+++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp
@@ -112,7 +112,7 @@ std::unique_ptr<DocumentSourceGraphLookUp::LiteParsed> DocumentSourceGraphLookUp
REGISTER_DOCUMENT_SOURCE(graphLookup,
DocumentSourceGraphLookUp::LiteParsed::parse,
DocumentSourceGraphLookUp::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
const char* DocumentSourceGraphLookUp::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_group.cpp b/src/mongo/db/pipeline/document_source_group.cpp
index 303db0418b9..72ad6448e9b 100644
--- a/src/mongo/db/pipeline/document_source_group.cpp
+++ b/src/mongo/db/pipeline/document_source_group.cpp
@@ -127,7 +127,7 @@ constexpr StringData DocumentSourceGroup::kStageName;
REGISTER_DOCUMENT_SOURCE(group,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceGroup::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
const char* DocumentSourceGroup::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_index_stats.cpp b/src/mongo/db/pipeline/document_source_index_stats.cpp
index ad6d600e74d..e87b614e59a 100644
--- a/src/mongo/db/pipeline/document_source_index_stats.cpp
+++ b/src/mongo/db/pipeline/document_source_index_stats.cpp
@@ -42,7 +42,7 @@ using boost::intrusive_ptr;
REGISTER_DOCUMENT_SOURCE(indexStats,
DocumentSourceIndexStats::LiteParsed::parse,
DocumentSourceIndexStats::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
const char* DocumentSourceIndexStats::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp b/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp
index 3e523696eb8..5e08827daef 100644
--- a/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_convert_bucket_index_stats.cpp
@@ -105,7 +105,7 @@ BSONObj makeTimeseriesIndexStats(const TimeseriesConversionOptions& bucketSpec,
REGISTER_DOCUMENT_SOURCE(_internalConvertBucketIndexStats,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalConvertBucketIndexStats::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kInternal);
+ AllowedWithApiStrict::kInternal);
DocumentSourceInternalConvertBucketIndexStats::DocumentSourceInternalConvertBucketIndexStats(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
diff --git a/src/mongo/db/pipeline/document_source_internal_inhibit_optimization.cpp b/src/mongo/db/pipeline/document_source_internal_inhibit_optimization.cpp
index 10f10171f06..af9d4c297b1 100644
--- a/src/mongo/db/pipeline/document_source_internal_inhibit_optimization.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_inhibit_optimization.cpp
@@ -36,7 +36,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(_internalInhibitOptimization,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalInhibitOptimization::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
constexpr StringData DocumentSourceInternalInhibitOptimization::kStageName;
diff --git a/src/mongo/db/pipeline/document_source_internal_split_pipeline.cpp b/src/mongo/db/pipeline/document_source_internal_split_pipeline.cpp
index c2721ff77d3..8f5f9927ada 100644
--- a/src/mongo/db/pipeline/document_source_internal_split_pipeline.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_split_pipeline.cpp
@@ -36,7 +36,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(_internalSplitPipeline,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalSplitPipeline::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
constexpr StringData DocumentSourceInternalSplitPipeline::kStageName;
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
index 2fa8291fee2..8ef46b46734 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
@@ -66,7 +66,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(_internalUnpackBucket,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalUnpackBucket::createFromBsonInternal,
- LiteParsedDocumentSource::AllowedWithApiStrict::kInternal);
+ AllowedWithApiStrict::kInternal);
/*
* $_unpackBucket is an alias of $_internalUnpackBucket. It only exposes the "timeField" and the
@@ -76,7 +76,7 @@ REGISTER_DOCUMENT_SOURCE(_internalUnpackBucket,
REGISTER_DOCUMENT_SOURCE(_unpackBucket,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalUnpackBucket::createFromBsonExternal,
- LiteParsedDocumentSource::AllowedWithApiStrict::kInternal);
+ AllowedWithApiStrict::kInternal);
namespace {
/**
diff --git a/src/mongo/db/pipeline/document_source_limit.cpp b/src/mongo/db/pipeline/document_source_limit.cpp
index 1f8051fa1d0..227fe4dc212 100644
--- a/src/mongo/db/pipeline/document_source_limit.cpp
+++ b/src/mongo/db/pipeline/document_source_limit.cpp
@@ -50,7 +50,7 @@ DocumentSourceLimit::DocumentSourceLimit(const intrusive_ptr<ExpressionContext>&
REGISTER_DOCUMENT_SOURCE(limit,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceLimit::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
constexpr StringData DocumentSourceLimit::kStageName;
diff --git a/src/mongo/db/pipeline/document_source_list_local_sessions.cpp b/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
index f9c329ff65e..d4e96fc135d 100644
--- a/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
+++ b/src/mongo/db/pipeline/document_source_list_local_sessions.cpp
@@ -40,7 +40,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(listLocalSessions,
DocumentSourceListLocalSessions::LiteParsed::parse,
DocumentSourceListLocalSessions::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
DocumentSource::GetNextResult DocumentSourceListLocalSessions::doGetNext() {
while (!_ids.empty()) {
diff --git a/src/mongo/db/pipeline/document_source_list_sessions.cpp b/src/mongo/db/pipeline/document_source_list_sessions.cpp
index 996856b3657..3c19beb4d5f 100644
--- a/src/mongo/db/pipeline/document_source_list_sessions.cpp
+++ b/src/mongo/db/pipeline/document_source_list_sessions.cpp
@@ -41,7 +41,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(listSessions,
DocumentSourceListSessions::LiteParsed::parse,
DocumentSourceListSessions::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
boost::intrusive_ptr<DocumentSource> DocumentSourceListSessions::createFromBson(
BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& pExpCtx) {
diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp
index aade4c22aae..d34df7f095a 100644
--- a/src/mongo/db/pipeline/document_source_lookup.cpp
+++ b/src/mongo/db/pipeline/document_source_lookup.cpp
@@ -294,7 +294,7 @@ PrivilegeVector DocumentSourceLookUp::LiteParsed::requiredPrivileges(
REGISTER_DOCUMENT_SOURCE(lookup,
DocumentSourceLookUp::LiteParsed::parse,
DocumentSourceLookUp::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kSometimes);
+ AllowedWithApiStrict::kSometimes);
const char* DocumentSourceLookUp::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp
index 6686626438b..8ab9a5c0ece 100644
--- a/src/mongo/db/pipeline/document_source_match.cpp
+++ b/src/mongo/db/pipeline/document_source_match.cpp
@@ -58,7 +58,7 @@ using std::vector;
REGISTER_DOCUMENT_SOURCE(match,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceMatch::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
const char* DocumentSourceMatch::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp
index 36f652c66cd..7fc546d864d 100644
--- a/src/mongo/db/pipeline/document_source_merge.cpp
+++ b/src/mongo/db/pipeline/document_source_merge.cpp
@@ -50,7 +50,7 @@ MONGO_FAIL_POINT_DEFINE(hangWhileBuildingDocumentSourceMergeBatch);
REGISTER_DOCUMENT_SOURCE(merge,
DocumentSourceMerge::LiteParsed::parse,
DocumentSourceMerge::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
namespace {
using MergeStrategyDescriptor = DocumentSourceMerge::MergeStrategyDescriptor;
diff --git a/src/mongo/db/pipeline/document_source_operation_metrics.cpp b/src/mongo/db/pipeline/document_source_operation_metrics.cpp
index 548a7b3679b..a5e523465e4 100644
--- a/src/mongo/db/pipeline/document_source_operation_metrics.cpp
+++ b/src/mongo/db/pipeline/document_source_operation_metrics.cpp
@@ -44,7 +44,7 @@ using boost::intrusive_ptr;
REGISTER_DOCUMENT_SOURCE(operationMetrics,
DocumentSourceOperationMetrics::LiteParsed::parse,
DocumentSourceOperationMetrics::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
const char* DocumentSourceOperationMetrics::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp
index 1fef7bb2bd2..5f97cbb0555 100644
--- a/src/mongo/db/pipeline/document_source_out.cpp
+++ b/src/mongo/db/pipeline/document_source_out.cpp
@@ -52,7 +52,7 @@ MONGO_FAIL_POINT_DEFINE(outWaitAfterTempCollectionCreation);
REGISTER_DOCUMENT_SOURCE(out,
DocumentSourceOut::LiteParsed::parse,
DocumentSourceOut::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
DocumentSourceOut::~DocumentSourceOut() {
DESTRUCTOR_GUARD(
diff --git a/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp b/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp
index bfbe60b4ec8..51f7bf3d650 100644
--- a/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp
+++ b/src/mongo/db/pipeline/document_source_plan_cache_stats.cpp
@@ -36,7 +36,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(planCacheStats,
DocumentSourcePlanCacheStats::LiteParsed::parse,
DocumentSourcePlanCacheStats::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1);
+ AllowedWithApiStrict::kNeverInVersion1);
boost::intrusive_ptr<DocumentSource> DocumentSourcePlanCacheStats::createFromBson(
BSONElement spec, const boost::intrusive_ptr<ExpressionContext>& pExpCtx) {
diff --git a/src/mongo/db/pipeline/document_source_project.cpp b/src/mongo/db/pipeline/document_source_project.cpp
index 3630cae3440..72c19be3c05 100644
--- a/src/mongo/db/pipeline/document_source_project.cpp
+++ b/src/mongo/db/pipeline/document_source_project.cpp
@@ -46,12 +46,12 @@ using boost::intrusive_ptr;
REGISTER_DOCUMENT_SOURCE(project,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceProject::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
REGISTER_DOCUMENT_SOURCE(unset,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceProject::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
namespace {
BSONObj buildExclusionProjectionSpecification(const std::vector<BSONElement>& unsetSpec) {
diff --git a/src/mongo/db/pipeline/document_source_redact.cpp b/src/mongo/db/pipeline/document_source_redact.cpp
index eaefcdf672b..80dc406c620 100644
--- a/src/mongo/db/pipeline/document_source_redact.cpp
+++ b/src/mongo/db/pipeline/document_source_redact.cpp
@@ -52,7 +52,7 @@ DocumentSourceRedact::DocumentSourceRedact(const intrusive_ptr<ExpressionContext
REGISTER_DOCUMENT_SOURCE(redact,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceRedact::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
const char* DocumentSourceRedact::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/document_source_replace_root.cpp b/src/mongo/db/pipeline/document_source_replace_root.cpp
index 084d7398fb9..137791a4ca7 100644
--- a/src/mongo/db/pipeline/document_source_replace_root.cpp
+++ b/src/mongo/db/pipeline/document_source_replace_root.cpp
@@ -77,11 +77,11 @@ Document ReplaceRootTransformation::applyTransformation(const Document& input) {
REGISTER_DOCUMENT_SOURCE(replaceRoot,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceReplaceRoot::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
REGISTER_DOCUMENT_SOURCE(replaceWith,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceReplaceRoot::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
intrusive_ptr<DocumentSource> DocumentSourceReplaceRoot::createFromBson(
BSONElement elem, const intrusive_ptr<ExpressionContext>& expCtx) {
diff --git a/src/mongo/db/pipeline/document_source_sample.cpp b/src/mongo/db/pipeline/document_source_sample.cpp
index 57d5661c388..6f3f95d16f1 100644
--- a/src/mongo/db/pipeline/document_source_sample.cpp
+++ b/src/mongo/db/pipeline/document_source_sample.cpp
@@ -49,7 +49,7 @@ DocumentSourceSample::DocumentSourceSample(const intrusive_ptr<ExpressionContext
REGISTER_DOCUMENT_SOURCE(sample,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceSample::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
DocumentSource::GetNextResult DocumentSourceSample::doGetNext() {
if (_size == 0)
diff --git a/src/mongo/db/pipeline/document_source_set_window_fields.cpp b/src/mongo/db/pipeline/document_source_set_window_fields.cpp
index 1e3f549edb7..ff728f14349 100644
--- a/src/mongo/db/pipeline/document_source_set_window_fields.cpp
+++ b/src/mongo/db/pipeline/document_source_set_window_fields.cpp
@@ -77,14 +77,14 @@ REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION(
setWindowFields,
LiteParsedDocumentSourceDefault::parse,
document_source_set_window_fields::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithApiStrict::kNeverInVersion1,
ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION(
_internalSetWindowFields,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceInternalSetWindowFields::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithApiStrict::kNeverInVersion1,
ServerGlobalParams::FeatureCompatibility::Version::kVersion50);
list<intrusive_ptr<DocumentSource>> document_source_set_window_fields::createFromBson(
diff --git a/src/mongo/db/pipeline/document_source_skip.cpp b/src/mongo/db/pipeline/document_source_skip.cpp
index 7fa58be38ec..df7537fd1dd 100644
--- a/src/mongo/db/pipeline/document_source_skip.cpp
+++ b/src/mongo/db/pipeline/document_source_skip.cpp
@@ -51,7 +51,7 @@ DocumentSourceSkip::DocumentSourceSkip(const intrusive_ptr<ExpressionContext>& p
REGISTER_DOCUMENT_SOURCE(skip,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceSkip::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
constexpr StringData DocumentSourceSkip::kStageName;
diff --git a/src/mongo/db/pipeline/document_source_sort.cpp b/src/mongo/db/pipeline/document_source_sort.cpp
index 1dc94d03efb..efbc3f3fe42 100644
--- a/src/mongo/db/pipeline/document_source_sort.cpp
+++ b/src/mongo/db/pipeline/document_source_sort.cpp
@@ -74,7 +74,7 @@ DocumentSourceSort::DocumentSourceSort(const boost::intrusive_ptr<ExpressionCont
REGISTER_DOCUMENT_SOURCE(sort,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceSort::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
DocumentSource::GetNextResult DocumentSourceSort::doGetNext() {
if (!_populated) {
diff --git a/src/mongo/db/pipeline/document_source_sort_by_count.cpp b/src/mongo/db/pipeline/document_source_sort_by_count.cpp
index d35ec06f33e..846a90e0fa9 100644
--- a/src/mongo/db/pipeline/document_source_sort_by_count.cpp
+++ b/src/mongo/db/pipeline/document_source_sort_by_count.cpp
@@ -45,7 +45,7 @@ using std::list;
REGISTER_DOCUMENT_SOURCE(sortByCount,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceSortByCount::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
list<intrusive_ptr<DocumentSource>> DocumentSourceSortByCount::createFromBson(
BSONElement elem, const intrusive_ptr<ExpressionContext>& pExpCtx) {
diff --git a/src/mongo/db/pipeline/document_source_union_with.cpp b/src/mongo/db/pipeline/document_source_union_with.cpp
index 17570253cda..9027c9b7224 100644
--- a/src/mongo/db/pipeline/document_source_union_with.cpp
+++ b/src/mongo/db/pipeline/document_source_union_with.cpp
@@ -45,7 +45,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(unionWith,
DocumentSourceUnionWith::LiteParsed::parse,
DocumentSourceUnionWith::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
namespace {
std::unique_ptr<Pipeline, PipelineDeleter> buildPipelineFromViewDefinition(
diff --git a/src/mongo/db/pipeline/document_source_unwind.cpp b/src/mongo/db/pipeline/document_source_unwind.cpp
index b08e6f7aec3..99509b93391 100644
--- a/src/mongo/db/pipeline/document_source_unwind.cpp
+++ b/src/mongo/db/pipeline/document_source_unwind.cpp
@@ -169,7 +169,7 @@ DocumentSourceUnwind::DocumentSourceUnwind(const intrusive_ptr<ExpressionContext
REGISTER_DOCUMENT_SOURCE(unwind,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceUnwind::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kAlways);
+ AllowedWithApiStrict::kAlways);
const char* DocumentSourceUnwind::getSourceName() const {
return kStageName.rawData();
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index 664c3f81425..068d78ecb55 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -110,6 +110,8 @@ intrusive_ptr<Expression> Expression::parseObject(ExpressionContext* const expCt
namespace {
struct ParserRegistration {
Parser parser;
+ AllowedWithApiStrict allowedWithApiStrict;
+ AllowedWithClientType allowedWithClientType;
boost::optional<ServerGlobalParams::FeatureCompatibility::Version> requiredMinVersion;
};
@@ -171,12 +173,15 @@ StringMap<ParserRegistration> parserMap;
void Expression::registerExpression(
string key,
Parser parser,
+ AllowedWithApiStrict allowedWithApiStrict,
+ AllowedWithClientType allowedWithClientType,
boost::optional<ServerGlobalParams::FeatureCompatibility::Version> requiredMinVersion) {
auto op = parserMap.find(key);
massert(17064,
str::stream() << "Duplicate expression (" << key << ") registered.",
op == parserMap.end());
- parserMap[key] = {parser, requiredMinVersion};
+ parserMap[key] =
+ ParserRegistration{parser, allowedWithApiStrict, allowedWithClientType, requiredMinVersion};
// Add this expression to the global map of operator counters for expressions.
operatorCountersExpressions.addExpressionCounter(key);
}
@@ -211,6 +216,14 @@ intrusive_ptr<Expression> Expression::parseExpression(ExpressionContext* const e
!expCtx->maxFeatureCompatibilityVersion || !entry.requiredMinVersion ||
(*entry.requiredMinVersion <= *expCtx->maxFeatureCompatibilityVersion));
+ if (expCtx->opCtx) {
+ // Only confirm API versioning if in a user operation, and not parsing a collection
+ // validator. Instead we perform checks for validators at time of access in subsequent
+ // insert/update.
+ assertLanguageFeatureIsAllowed(
+ expCtx->opCtx, opName, entry.allowedWithApiStrict, entry.allowedWithClientType);
+ }
+
// Increment the global counter for this expression.
operatorCountersExpressions.incrementExpressionCounter(opName);
return entry.parser(expCtx, obj.firstElement(), vps);
@@ -254,19 +267,19 @@ bool Expression::isExpressionName(StringData name) {
/* ------------------------- Register Date Expressions ----------------------------- */
-REGISTER_EXPRESSION(dayOfMonth, ExpressionDayOfMonth::parse);
-REGISTER_EXPRESSION(dayOfWeek, ExpressionDayOfWeek::parse);
-REGISTER_EXPRESSION(dayOfYear, ExpressionDayOfYear::parse);
-REGISTER_EXPRESSION(hour, ExpressionHour::parse);
-REGISTER_EXPRESSION(isoDayOfWeek, ExpressionIsoDayOfWeek::parse);
-REGISTER_EXPRESSION(isoWeek, ExpressionIsoWeek::parse);
-REGISTER_EXPRESSION(isoWeekYear, ExpressionIsoWeekYear::parse);
-REGISTER_EXPRESSION(millisecond, ExpressionMillisecond::parse);
-REGISTER_EXPRESSION(minute, ExpressionMinute::parse);
-REGISTER_EXPRESSION(month, ExpressionMonth::parse);
-REGISTER_EXPRESSION(second, ExpressionSecond::parse);
-REGISTER_EXPRESSION(week, ExpressionWeek::parse);
-REGISTER_EXPRESSION(year, ExpressionYear::parse);
+REGISTER_STABLE_EXPRESSION(dayOfMonth, ExpressionDayOfMonth::parse);
+REGISTER_STABLE_EXPRESSION(dayOfWeek, ExpressionDayOfWeek::parse);
+REGISTER_STABLE_EXPRESSION(dayOfYear, ExpressionDayOfYear::parse);
+REGISTER_STABLE_EXPRESSION(hour, ExpressionHour::parse);
+REGISTER_STABLE_EXPRESSION(isoDayOfWeek, ExpressionIsoDayOfWeek::parse);
+REGISTER_STABLE_EXPRESSION(isoWeek, ExpressionIsoWeek::parse);
+REGISTER_STABLE_EXPRESSION(isoWeekYear, ExpressionIsoWeekYear::parse);
+REGISTER_STABLE_EXPRESSION(millisecond, ExpressionMillisecond::parse);
+REGISTER_STABLE_EXPRESSION(minute, ExpressionMinute::parse);
+REGISTER_STABLE_EXPRESSION(month, ExpressionMonth::parse);
+REGISTER_STABLE_EXPRESSION(second, ExpressionSecond::parse);
+REGISTER_STABLE_EXPRESSION(week, ExpressionWeek::parse);
+REGISTER_STABLE_EXPRESSION(year, ExpressionYear::parse);
/* ----------------------- ExpressionAbs ---------------------------- */
@@ -286,7 +299,7 @@ Value ExpressionAbs::evaluateNumericArg(const Value& numericArg) const {
}
}
-REGISTER_EXPRESSION(abs, ExpressionAbs::parse);
+REGISTER_STABLE_EXPRESSION(abs, ExpressionAbs::parse);
const char* ExpressionAbs::getOpName() const {
return "$abs";
}
@@ -400,7 +413,7 @@ Value ExpressionAdd::evaluate(const Document& root, Variables* variables) const
}
}
-REGISTER_EXPRESSION(add, ExpressionAdd::parse);
+REGISTER_STABLE_EXPRESSION(add, ExpressionAdd::parse);
const char* ExpressionAdd::getOpName() const {
return "$add";
}
@@ -422,7 +435,7 @@ Value ExpressionAllElementsTrue::evaluate(const Document& root, Variables* varia
return Value(true);
}
-REGISTER_EXPRESSION(allElementsTrue, ExpressionAllElementsTrue::parse);
+REGISTER_STABLE_EXPRESSION(allElementsTrue, ExpressionAllElementsTrue::parse);
const char* ExpressionAllElementsTrue::getOpName() const {
return "$allElementsTrue";
}
@@ -496,7 +509,7 @@ Value ExpressionAnd::evaluate(const Document& root, Variables* variables) const
return Value(true);
}
-REGISTER_EXPRESSION(and, ExpressionAnd::parse);
+REGISTER_STABLE_EXPRESSION(and, ExpressionAnd::parse);
const char* ExpressionAnd::getOpName() const {
return "$and";
}
@@ -518,7 +531,7 @@ Value ExpressionAnyElementTrue::evaluate(const Document& root, Variables* variab
return Value(false);
}
-REGISTER_EXPRESSION(anyElementTrue, ExpressionAnyElementTrue::parse);
+REGISTER_STABLE_EXPRESSION(anyElementTrue, ExpressionAnyElementTrue::parse);
const char* ExpressionAnyElementTrue::getOpName() const {
return "$anyElementTrue";
}
@@ -609,7 +622,7 @@ Value ExpressionArrayElemAt::evaluate(const Document& root, Variables* variables
return arrayElemAt(this, array, indexArg);
}
-REGISTER_EXPRESSION(arrayElemAt, ExpressionArrayElemAt::parse);
+REGISTER_STABLE_EXPRESSION(arrayElemAt, ExpressionArrayElemAt::parse);
const char* ExpressionArrayElemAt::getOpName() const {
return "$arrayElemAt";
}
@@ -621,7 +634,7 @@ Value ExpressionFirst::evaluate(const Document& root, Variables* variables) cons
return arrayElemAt(this, array, Value(0));
}
-REGISTER_EXPRESSION(first, ExpressionFirst::parse);
+REGISTER_STABLE_EXPRESSION(first, ExpressionFirst::parse);
const char* ExpressionFirst::getOpName() const {
return "$first";
@@ -634,7 +647,7 @@ Value ExpressionLast::evaluate(const Document& root, Variables* variables) const
return arrayElemAt(this, array, Value(-1));
}
-REGISTER_EXPRESSION(last, ExpressionLast::parse);
+REGISTER_STABLE_EXPRESSION(last, ExpressionLast::parse);
const char* ExpressionLast::getOpName() const {
return "$last";
@@ -668,7 +681,7 @@ Value ExpressionObjectToArray::evaluate(const Document& root, Variables* variabl
return Value(output);
}
-REGISTER_EXPRESSION(objectToArray, ExpressionObjectToArray::parse);
+REGISTER_STABLE_EXPRESSION(objectToArray, ExpressionObjectToArray::parse);
const char* ExpressionObjectToArray::getOpName() const {
return "$objectToArray";
}
@@ -779,14 +792,14 @@ Value ExpressionArrayToObject::evaluate(const Document& root, Variables* variabl
return output.freezeToValue();
}
-REGISTER_EXPRESSION(arrayToObject, ExpressionArrayToObject::parse);
+REGISTER_STABLE_EXPRESSION(arrayToObject, ExpressionArrayToObject::parse);
const char* ExpressionArrayToObject::getOpName() const {
return "$arrayToObject";
}
/* ------------------------- ExpressionBsonSize -------------------------- */
-REGISTER_EXPRESSION(bsonSize, ExpressionBsonSize::parse);
+REGISTER_STABLE_EXPRESSION(bsonSize, ExpressionBsonSize::parse);
Value ExpressionBsonSize::evaluate(const Document& root, Variables* variables) const {
Value arg = _children[0]->evaluate(root, variables);
@@ -818,7 +831,7 @@ Value ExpressionCeil::evaluateNumericArg(const Value& numericArg) const {
}
}
-REGISTER_EXPRESSION(ceil, ExpressionCeil::parse);
+REGISTER_STABLE_EXPRESSION(ceil, ExpressionCeil::parse);
const char* ExpressionCeil::getOpName() const {
return "$ceil";
}
@@ -881,13 +894,13 @@ struct BoundOp {
};
} // namespace
-REGISTER_EXPRESSION(cmp, BoundOp{ExpressionCompare::CMP});
-REGISTER_EXPRESSION(eq, BoundOp{ExpressionCompare::EQ});
-REGISTER_EXPRESSION(gt, BoundOp{ExpressionCompare::GT});
-REGISTER_EXPRESSION(gte, BoundOp{ExpressionCompare::GTE});
-REGISTER_EXPRESSION(lt, BoundOp{ExpressionCompare::LT});
-REGISTER_EXPRESSION(lte, BoundOp{ExpressionCompare::LTE});
-REGISTER_EXPRESSION(ne, BoundOp{ExpressionCompare::NE});
+REGISTER_STABLE_EXPRESSION(cmp, BoundOp{ExpressionCompare::CMP});
+REGISTER_STABLE_EXPRESSION(eq, BoundOp{ExpressionCompare::EQ});
+REGISTER_STABLE_EXPRESSION(gt, BoundOp{ExpressionCompare::GT});
+REGISTER_STABLE_EXPRESSION(gte, BoundOp{ExpressionCompare::GTE});
+REGISTER_STABLE_EXPRESSION(lt, BoundOp{ExpressionCompare::LT});
+REGISTER_STABLE_EXPRESSION(lte, BoundOp{ExpressionCompare::LTE});
+REGISTER_STABLE_EXPRESSION(ne, BoundOp{ExpressionCompare::NE});
intrusive_ptr<Expression> ExpressionCompare::parse(ExpressionContext* const expCtx,
BSONElement bsonExpr,
@@ -978,7 +991,7 @@ Value ExpressionConcat::evaluate(const Document& root, Variables* variables) con
return Value(result.str());
}
-REGISTER_EXPRESSION(concat, ExpressionConcat::parse);
+REGISTER_STABLE_EXPRESSION(concat, ExpressionConcat::parse);
const char* ExpressionConcat::getOpName() const {
return "$concat";
}
@@ -1006,7 +1019,7 @@ Value ExpressionConcatArrays::evaluate(const Document& root, Variables* variable
return Value(std::move(values));
}
-REGISTER_EXPRESSION(concatArrays, ExpressionConcatArrays::parse);
+REGISTER_STABLE_EXPRESSION(concatArrays, ExpressionConcatArrays::parse);
const char* ExpressionConcatArrays::getOpName() const {
return "$concatArrays";
}
@@ -1051,7 +1064,7 @@ intrusive_ptr<Expression> ExpressionCond::parse(ExpressionContext* const expCtx,
return ret;
}
-REGISTER_EXPRESSION(cond, ExpressionCond::parse);
+REGISTER_STABLE_EXPRESSION(cond, ExpressionCond::parse);
const char* ExpressionCond::getOpName() const {
return "$cond";
}
@@ -1092,8 +1105,8 @@ Value ExpressionConstant::serialize(bool explain) const {
return serializeConstant(_value);
}
-REGISTER_EXPRESSION(const, ExpressionConstant::parse);
-REGISTER_EXPRESSION(literal, ExpressionConstant::parse); // alias
+REGISTER_STABLE_EXPRESSION(const, ExpressionConstant::parse);
+REGISTER_STABLE_EXPRESSION(literal, ExpressionConstant::parse); // alias
const char* ExpressionConstant::getOpName() const {
return "$const";
}
@@ -1131,7 +1144,7 @@ boost::optional<TimeZone> makeTimeZone(const TimeZoneDatabase* tzdb,
} // namespace
-REGISTER_EXPRESSION(dateFromParts, ExpressionDateFromParts::parse);
+REGISTER_STABLE_EXPRESSION(dateFromParts, ExpressionDateFromParts::parse);
intrusive_ptr<Expression> ExpressionDateFromParts::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -1469,7 +1482,7 @@ void ExpressionDateFromParts::_doAddDependencies(DepsTracker* deps) const {
/* ---------------------- ExpressionDateFromString --------------------- */
-REGISTER_EXPRESSION(dateFromString, ExpressionDateFromString::parse);
+REGISTER_STABLE_EXPRESSION(dateFromString, ExpressionDateFromString::parse);
intrusive_ptr<Expression> ExpressionDateFromString::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -1652,7 +1665,7 @@ void ExpressionDateFromString::_doAddDependencies(DepsTracker* deps) const {
/* ---------------------- ExpressionDateToParts ----------------------- */
-REGISTER_EXPRESSION(dateToParts, ExpressionDateToParts::parse);
+REGISTER_STABLE_EXPRESSION(dateToParts, ExpressionDateToParts::parse);
intrusive_ptr<Expression> ExpressionDateToParts::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -1800,7 +1813,7 @@ void ExpressionDateToParts::_doAddDependencies(DepsTracker* deps) const {
/* ---------------------- ExpressionDateToString ----------------------- */
-REGISTER_EXPRESSION(dateToString, ExpressionDateToString::parse);
+REGISTER_STABLE_EXPRESSION(dateToString, ExpressionDateToString::parse);
intrusive_ptr<Expression> ExpressionDateToString::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -1949,6 +1962,8 @@ void ExpressionDateToString::_doAddDependencies(DepsTracker* deps) const {
// TODO SERVER-53028: make the expression to be available for any FCV when 5.0 becomes last-lts.
REGISTER_EXPRESSION_WITH_MIN_VERSION(dateDiff,
ExpressionDateDiff::parse,
+ AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithClientType::kAny,
ServerGlobalParams::FeatureCompatibility::Version::kVersion49);
ExpressionDateDiff::ExpressionDateDiff(ExpressionContext* const expCtx,
@@ -2129,7 +2144,7 @@ StatusWith<Value> ExpressionDivide::apply(Value lhs, Value rhs) {
}
}
-REGISTER_EXPRESSION(divide, ExpressionDivide::parse);
+REGISTER_STABLE_EXPRESSION(divide, ExpressionDivide::parse);
const char* ExpressionDivide::getOpName() const {
return "$divide";
}
@@ -2144,7 +2159,7 @@ Value ExpressionExp::evaluateNumericArg(const Value& numericArg) const {
return Value(exp(numericArg.coerceToDouble()));
}
-REGISTER_EXPRESSION(exp, ExpressionExp::parse);
+REGISTER_STABLE_EXPRESSION(exp, ExpressionExp::parse);
const char* ExpressionExp::getOpName() const {
return "$exp";
}
@@ -2465,7 +2480,7 @@ std::unique_ptr<Expression> ExpressionFieldPath::copyWithSubstitution(
/* ------------------------- ExpressionFilter ----------------------------- */
-REGISTER_EXPRESSION(filter, ExpressionFilter::parse);
+REGISTER_STABLE_EXPRESSION(filter, ExpressionFilter::parse);
intrusive_ptr<Expression> ExpressionFilter::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -2584,14 +2599,14 @@ Value ExpressionFloor::evaluateNumericArg(const Value& numericArg) const {
}
}
-REGISTER_EXPRESSION(floor, ExpressionFloor::parse);
+REGISTER_STABLE_EXPRESSION(floor, ExpressionFloor::parse);
const char* ExpressionFloor::getOpName() const {
return "$floor";
}
/* ------------------------- ExpressionLet ----------------------------- */
-REGISTER_EXPRESSION(let, ExpressionLet::parse);
+REGISTER_STABLE_EXPRESSION(let, ExpressionLet::parse);
intrusive_ptr<Expression> ExpressionLet::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -2705,7 +2720,7 @@ void ExpressionLet::_doAddDependencies(DepsTracker* deps) const {
/* ------------------------- ExpressionMap ----------------------------- */
-REGISTER_EXPRESSION(map, ExpressionMap::parse);
+REGISTER_STABLE_EXPRESSION(map, ExpressionMap::parse);
intrusive_ptr<Expression> ExpressionMap::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -2845,7 +2860,7 @@ Expression::ComputedPaths ExpressionMap::getComputedPaths(const std::string& exp
/* ------------------------- ExpressionMeta ----------------------------- */
-REGISTER_EXPRESSION(meta, ExpressionMeta::parse);
+REGISTER_STABLE_EXPRESSION(meta, ExpressionMeta::parse);
namespace {
const std::string textScoreName = "textScore";
@@ -3018,7 +3033,7 @@ Value ExpressionMod::evaluate(const Document& root, Variables* variables) const
}
}
-REGISTER_EXPRESSION(mod, ExpressionMod::parse);
+REGISTER_STABLE_EXPRESSION(mod, ExpressionMod::parse);
const char* ExpressionMod::getOpName() const {
return "$mod";
}
@@ -3115,7 +3130,7 @@ Value ExpressionMultiply::evaluate(const Document& root, Variables* variables) c
return state.getValue();
}
-REGISTER_EXPRESSION(multiply, ExpressionMultiply::parse);
+REGISTER_STABLE_EXPRESSION(multiply, ExpressionMultiply::parse);
const char* ExpressionMultiply::getOpName() const {
return "$multiply";
}
@@ -3138,7 +3153,7 @@ Value ExpressionIfNull::evaluate(const Document& root, Variables* variables) con
return Value();
}
-REGISTER_EXPRESSION(ifNull, ExpressionIfNull::parse);
+REGISTER_STABLE_EXPRESSION(ifNull, ExpressionIfNull::parse);
const char* ExpressionIfNull::getOpName() const {
return "$ifNull";
}
@@ -3161,7 +3176,7 @@ Value ExpressionIn::evaluate(const Document& root, Variables* variables) const {
return Value(false);
}
-REGISTER_EXPRESSION(in, ExpressionIn::parse);
+REGISTER_STABLE_EXPRESSION(in, ExpressionIn::parse);
const char* ExpressionIn::getOpName() const {
return "$in";
}
@@ -3310,7 +3325,7 @@ intrusive_ptr<Expression> ExpressionIndexOfArray::optimize() {
return this;
}
-REGISTER_EXPRESSION(indexOfArray, ExpressionIndexOfArray::parse);
+REGISTER_STABLE_EXPRESSION(indexOfArray, ExpressionIndexOfArray::parse);
const char* ExpressionIndexOfArray::getOpName() const {
return "$indexOfArray";
}
@@ -3375,7 +3390,7 @@ Value ExpressionIndexOfBytes::evaluate(const Document& root, Variables* variable
return Value(static_cast<int>(position));
}
-REGISTER_EXPRESSION(indexOfBytes, ExpressionIndexOfBytes::parse);
+REGISTER_STABLE_EXPRESSION(indexOfBytes, ExpressionIndexOfBytes::parse);
const char* ExpressionIndexOfBytes::getOpName() const {
return "$indexOfBytes";
}
@@ -3463,7 +3478,7 @@ Value ExpressionIndexOfCP::evaluate(const Document& root, Variables* variables)
return Value(-1);
}
-REGISTER_EXPRESSION(indexOfCP, ExpressionIndexOfCP::parse);
+REGISTER_STABLE_EXPRESSION(indexOfCP, ExpressionIndexOfCP::parse);
const char* ExpressionIndexOfCP::getOpName() const {
return "$indexOfCP";
}
@@ -3484,7 +3499,7 @@ Value ExpressionLn::evaluateNumericArg(const Value& numericArg) const {
return Value(std::log(argDouble));
}
-REGISTER_EXPRESSION(ln, ExpressionLn::parse);
+REGISTER_STABLE_EXPRESSION(ln, ExpressionLn::parse);
const char* ExpressionLn::getOpName() const {
return "$ln";
}
@@ -3528,7 +3543,7 @@ Value ExpressionLog::evaluate(const Document& root, Variables* variables) const
return Value(std::log(argDouble) / std::log(baseDouble));
}
-REGISTER_EXPRESSION(log, ExpressionLog::parse);
+REGISTER_STABLE_EXPRESSION(log, ExpressionLog::parse);
const char* ExpressionLog::getOpName() const {
return "$log";
}
@@ -3550,7 +3565,7 @@ Value ExpressionLog10::evaluateNumericArg(const Value& numericArg) const {
return Value(std::log10(argDouble));
}
-REGISTER_EXPRESSION(log10, ExpressionLog10::parse);
+REGISTER_STABLE_EXPRESSION(log10, ExpressionLog10::parse);
const char* ExpressionLog10::getOpName() const {
return "$log10";
}
@@ -3687,7 +3702,7 @@ Value ExpressionNot::evaluate(const Document& root, Variables* variables) const
return Value(!b);
}
-REGISTER_EXPRESSION(not, ExpressionNot::parse);
+REGISTER_STABLE_EXPRESSION(not, ExpressionNot::parse);
const char* ExpressionNot::getOpName() const {
return "$not";
}
@@ -3757,7 +3772,7 @@ intrusive_ptr<Expression> ExpressionOr::optimize() {
return pE;
}
-REGISTER_EXPRESSION(or, ExpressionOr::parse);
+REGISTER_STABLE_EXPRESSION(or, ExpressionOr::parse);
const char* ExpressionOr::getOpName() const {
return "$or";
}
@@ -3979,7 +3994,7 @@ Value ExpressionPow::evaluate(const Document& root, Variables* variables) const
return formatResult(computeWithRepeatedMultiplication(baseLong, expLong));
}
-REGISTER_EXPRESSION(pow, ExpressionPow::parse);
+REGISTER_STABLE_EXPRESSION(pow, ExpressionPow::parse);
const char* ExpressionPow::getOpName() const {
return "$pow";
}
@@ -4041,14 +4056,14 @@ Value ExpressionRange::evaluate(const Document& root, Variables* variables) cons
return Value(output);
}
-REGISTER_EXPRESSION(range, ExpressionRange::parse);
+REGISTER_STABLE_EXPRESSION(range, ExpressionRange::parse);
const char* ExpressionRange::getOpName() const {
return "$range";
}
/* ------------------------ ExpressionReduce ------------------------------ */
-REGISTER_EXPRESSION(reduce, ExpressionReduce::parse);
+REGISTER_STABLE_EXPRESSION(reduce, ExpressionReduce::parse);
intrusive_ptr<Expression> ExpressionReduce::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -4224,7 +4239,7 @@ intrusive_ptr<Expression> ExpressionReplaceBase::optimize() {
/* ------------------------ ExpressionReplaceOne ------------------------ */
-REGISTER_EXPRESSION(replaceOne, ExpressionReplaceOne::parse);
+REGISTER_STABLE_EXPRESSION(replaceOne, ExpressionReplaceOne::parse);
intrusive_ptr<Expression> ExpressionReplaceOne::parse(ExpressionContext* const expCtx,
BSONElement expr,
@@ -4255,7 +4270,7 @@ Value ExpressionReplaceOne::_doEval(StringData input,
/* ------------------------ ExpressionReplaceAll ------------------------ */
-REGISTER_EXPRESSION(replaceAll, ExpressionReplaceAll::parse);
+REGISTER_STABLE_EXPRESSION(replaceAll, ExpressionReplaceAll::parse);
intrusive_ptr<Expression> ExpressionReplaceAll::parse(ExpressionContext* const expCtx,
BSONElement expr,
@@ -4321,7 +4336,7 @@ Value ExpressionReverseArray::evaluate(const Document& root, Variables* variable
return Value(array);
}
-REGISTER_EXPRESSION(reverseArray, ExpressionReverseArray::parse);
+REGISTER_STABLE_EXPRESSION(reverseArray, ExpressionReverseArray::parse);
const char* ExpressionReverseArray::getOpName() const {
return "$reverseArray";
}
@@ -4368,7 +4383,7 @@ Value ExpressionSetDifference::evaluate(const Document& root, Variables* variabl
return Value(std::move(returnVec));
}
-REGISTER_EXPRESSION(setDifference, ExpressionSetDifference::parse);
+REGISTER_STABLE_EXPRESSION(setDifference, ExpressionSetDifference::parse);
const char* ExpressionSetDifference::getOpName() const {
return "$setDifference";
}
@@ -4410,7 +4425,7 @@ Value ExpressionSetEquals::evaluate(const Document& root, Variables* variables)
return Value(true);
}
-REGISTER_EXPRESSION(setEquals, ExpressionSetEquals::parse);
+REGISTER_STABLE_EXPRESSION(setEquals, ExpressionSetEquals::parse);
const char* ExpressionSetEquals::getOpName() const {
return "$setEquals";
}
@@ -4454,7 +4469,7 @@ Value ExpressionSetIntersection::evaluate(const Document& root, Variables* varia
return Value(vector<Value>(currentIntersection.begin(), currentIntersection.end()));
}
-REGISTER_EXPRESSION(setIntersection, ExpressionSetIntersection::parse);
+REGISTER_STABLE_EXPRESSION(setIntersection, ExpressionSetIntersection::parse);
const char* ExpressionSetIntersection::getOpName() const {
return "$setIntersection";
}
@@ -4546,7 +4561,7 @@ intrusive_ptr<Expression> ExpressionSetIsSubset::optimize() {
return optimized;
}
-REGISTER_EXPRESSION(setIsSubset, ExpressionSetIsSubset::parse);
+REGISTER_STABLE_EXPRESSION(setIsSubset, ExpressionSetIsSubset::parse);
const char* ExpressionSetIsSubset::getOpName() const {
return "$setIsSubset";
}
@@ -4571,7 +4586,7 @@ Value ExpressionSetUnion::evaluate(const Document& root, Variables* variables) c
return Value(vector<Value>(unionedSet.begin(), unionedSet.end()));
}
-REGISTER_EXPRESSION(setUnion, ExpressionSetUnion::parse);
+REGISTER_STABLE_EXPRESSION(setUnion, ExpressionSetUnion::parse);
const char* ExpressionSetUnion::getOpName() const {
return "$setUnion";
}
@@ -4583,7 +4598,7 @@ Value ExpressionIsArray::evaluate(const Document& root, Variables* variables) co
return Value(argument.isArray());
}
-REGISTER_EXPRESSION(isArray, ExpressionIsArray::parse);
+REGISTER_STABLE_EXPRESSION(isArray, ExpressionIsArray::parse);
const char* ExpressionIsArray::getOpName() const {
return "$isArray";
}
@@ -4669,7 +4684,7 @@ Value ExpressionSlice::evaluate(const Document& root, Variables* variables) cons
return Value(vector<Value>(array.begin() + start, array.begin() + end));
}
-REGISTER_EXPRESSION(slice, ExpressionSlice::parse);
+REGISTER_STABLE_EXPRESSION(slice, ExpressionSlice::parse);
const char* ExpressionSlice::getOpName() const {
return "$slice";
}
@@ -4686,7 +4701,7 @@ Value ExpressionSize::evaluate(const Document& root, Variables* variables) const
return Value::createIntOrLong(array.getArray().size());
}
-REGISTER_EXPRESSION(size, ExpressionSize::parse);
+REGISTER_STABLE_EXPRESSION(size, ExpressionSize::parse);
const char* ExpressionSize::getOpName() const {
return "$size";
}
@@ -4736,7 +4751,7 @@ Value ExpressionSplit::evaluate(const Document& root, Variables* variables) cons
return Value(std::move(output));
}
-REGISTER_EXPRESSION(split, ExpressionSplit::parse);
+REGISTER_STABLE_EXPRESSION(split, ExpressionSplit::parse);
const char* ExpressionSplit::getOpName() const {
return "$split";
}
@@ -4758,7 +4773,7 @@ Value ExpressionSqrt::evaluateNumericArg(const Value& numericArg) const {
return Value(sqrt(argDouble));
}
-REGISTER_EXPRESSION(sqrt, ExpressionSqrt::parse);
+REGISTER_STABLE_EXPRESSION(sqrt, ExpressionSqrt::parse);
const char* ExpressionSqrt::getOpName() const {
return "$sqrt";
}
@@ -4782,7 +4797,7 @@ Value ExpressionStrcasecmp::evaluate(const Document& root, Variables* variables)
return Value(-1);
}
-REGISTER_EXPRESSION(strcasecmp, ExpressionStrcasecmp::parse);
+REGISTER_STABLE_EXPRESSION(strcasecmp, ExpressionStrcasecmp::parse);
const char* ExpressionStrcasecmp::getOpName() const {
return "$strcasecmp";
}
@@ -4841,8 +4856,8 @@ Value ExpressionSubstrBytes::evaluate(const Document& root, Variables* variables
}
// $substr is deprecated in favor of $substrBytes, but for now will just parse into a $substrBytes.
-REGISTER_EXPRESSION(substrBytes, ExpressionSubstrBytes::parse);
-REGISTER_EXPRESSION(substr, ExpressionSubstrBytes::parse);
+REGISTER_STABLE_EXPRESSION(substrBytes, ExpressionSubstrBytes::parse);
+REGISTER_STABLE_EXPRESSION(substr, ExpressionSubstrBytes::parse);
const char* ExpressionSubstrBytes::getOpName() const {
return "$substrBytes";
}
@@ -4915,7 +4930,7 @@ Value ExpressionSubstrCP::evaluate(const Document& root, Variables* variables) c
return Value(std::string(str, startIndexBytes, endIndexBytes - startIndexBytes));
}
-REGISTER_EXPRESSION(substrCP, ExpressionSubstrCP::parse);
+REGISTER_STABLE_EXPRESSION(substrCP, ExpressionSubstrCP::parse);
const char* ExpressionSubstrCP::getOpName() const {
return "$substrCP";
}
@@ -4944,7 +4959,7 @@ Value ExpressionStrLenBytes::evaluate(const Document& root, Variables* variables
return strLenBytes(str.getStringData());
}
-REGISTER_EXPRESSION(strLenBytes, ExpressionStrLenBytes::parse);
+REGISTER_STABLE_EXPRESSION(strLenBytes, ExpressionStrLenBytes::parse);
const char* ExpressionStrLenBytes::getOpName() const {
return "$strLenBytes";
}
@@ -4970,7 +4985,7 @@ Value ExpressionBinarySize::evaluate(const Document& root, Variables* variables)
return Value(binData.length);
}
-REGISTER_EXPRESSION(binarySize, ExpressionBinarySize::parse);
+REGISTER_STABLE_EXPRESSION(binarySize, ExpressionBinarySize::parse);
const char* ExpressionBinarySize::getOpName() const {
return "$binarySize";
@@ -4996,7 +5011,7 @@ Value ExpressionStrLenCP::evaluate(const Document& root, Variables* variables) c
return Value(static_cast<int>(strLen));
}
-REGISTER_EXPRESSION(strLenCP, ExpressionStrLenCP::parse);
+REGISTER_STABLE_EXPRESSION(strLenCP, ExpressionStrLenCP::parse);
const char* ExpressionStrLenCP::getOpName() const {
return "$strLenCP";
}
@@ -5050,14 +5065,14 @@ StatusWith<Value> ExpressionSubtract::apply(Value lhs, Value rhs) {
}
}
-REGISTER_EXPRESSION(subtract, ExpressionSubtract::parse);
+REGISTER_STABLE_EXPRESSION(subtract, ExpressionSubtract::parse);
const char* ExpressionSubtract::getOpName() const {
return "$subtract";
}
/* ------------------------- ExpressionSwitch ------------------------------ */
-REGISTER_EXPRESSION(switch, ExpressionSwitch::parse);
+REGISTER_STABLE_EXPRESSION(switch, ExpressionSwitch::parse);
Value ExpressionSwitch::evaluate(const Document& root, Variables* variables) const {
for (auto&& branch : _branches) {
@@ -5201,7 +5216,7 @@ Value ExpressionToLower::evaluate(const Document& root, Variables* variables) co
return Value(str);
}
-REGISTER_EXPRESSION(toLower, ExpressionToLower::parse);
+REGISTER_STABLE_EXPRESSION(toLower, ExpressionToLower::parse);
const char* ExpressionToLower::getOpName() const {
return "$toLower";
}
@@ -5215,16 +5230,16 @@ Value ExpressionToUpper::evaluate(const Document& root, Variables* variables) co
return Value(str);
}
-REGISTER_EXPRESSION(toUpper, ExpressionToUpper::parse);
+REGISTER_STABLE_EXPRESSION(toUpper, ExpressionToUpper::parse);
const char* ExpressionToUpper::getOpName() const {
return "$toUpper";
}
/* -------------------------- ExpressionTrim ------------------------------ */
-REGISTER_EXPRESSION(trim, ExpressionTrim::parse);
-REGISTER_EXPRESSION(ltrim, ExpressionTrim::parse);
-REGISTER_EXPRESSION(rtrim, ExpressionTrim::parse);
+REGISTER_STABLE_EXPRESSION(trim, ExpressionTrim::parse);
+REGISTER_STABLE_EXPRESSION(ltrim, ExpressionTrim::parse);
+REGISTER_STABLE_EXPRESSION(rtrim, ExpressionTrim::parse);
intrusive_ptr<Expression> ExpressionTrim::parse(ExpressionContext* const expCtx,
BSONElement expr,
@@ -5534,7 +5549,7 @@ Value ExpressionRound::evaluate(const Document& root, Variables* variables) cons
root, _children, getOpName(), Decimal128::kRoundTiesToEven, &std::round, variables);
}
-REGISTER_EXPRESSION(round, ExpressionRound::parse);
+REGISTER_STABLE_EXPRESSION(round, ExpressionRound::parse);
const char* ExpressionRound::getOpName() const {
return "$round";
}
@@ -5550,7 +5565,7 @@ intrusive_ptr<Expression> ExpressionTrunc::parse(ExpressionContext* const expCtx
return ExpressionRangedArity<ExpressionTrunc, 1, 2>::parse(expCtx, elem, vps);
}
-REGISTER_EXPRESSION(trunc, ExpressionTrunc::parse);
+REGISTER_STABLE_EXPRESSION(trunc, ExpressionTrunc::parse);
const char* ExpressionTrunc::getOpName() const {
return "$trunc";
}
@@ -5562,7 +5577,7 @@ Value ExpressionType::evaluate(const Document& root, Variables* variables) const
return Value(StringData(typeName(val.getType())));
}
-REGISTER_EXPRESSION(type, ExpressionType::parse);
+REGISTER_STABLE_EXPRESSION(type, ExpressionType::parse);
const char* ExpressionType::getOpName() const {
return "$type";
}
@@ -5574,7 +5589,7 @@ Value ExpressionIsNumber::evaluate(const Document& root, Variables* variables) c
return Value(val.numeric());
}
-REGISTER_EXPRESSION(isNumber, ExpressionIsNumber::parse);
+REGISTER_STABLE_EXPRESSION(isNumber, ExpressionIsNumber::parse);
const char* ExpressionIsNumber::getOpName() const {
return "$isNumber";
@@ -5582,7 +5597,7 @@ const char* ExpressionIsNumber::getOpName() const {
/* -------------------------- ExpressionZip ------------------------------ */
-REGISTER_EXPRESSION(zip, ExpressionZip::parse);
+REGISTER_STABLE_EXPRESSION(zip, ExpressionZip::parse);
intrusive_ptr<Expression> ExpressionZip::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vps) {
@@ -6190,18 +6205,19 @@ Expression::Parser makeConversionAlias(const StringData shortcutName, BSONType t
} // namespace
-REGISTER_EXPRESSION(convert, ExpressionConvert::parse);
+REGISTER_STABLE_EXPRESSION(convert, ExpressionConvert::parse);
// Also register shortcut expressions like $toInt, $toString, etc. which can be used as a shortcut
// for $convert without an 'onNull' or 'onError'.
-REGISTER_EXPRESSION(toString, makeConversionAlias("$toString"_sd, BSONType::String));
-REGISTER_EXPRESSION(toObjectId, makeConversionAlias("$toObjectId"_sd, BSONType::jstOID));
-REGISTER_EXPRESSION(toDate, makeConversionAlias("$toDate"_sd, BSONType::Date));
-REGISTER_EXPRESSION(toDouble, makeConversionAlias("$toDouble"_sd, BSONType::NumberDouble));
-REGISTER_EXPRESSION(toInt, makeConversionAlias("$toInt"_sd, BSONType::NumberInt));
-REGISTER_EXPRESSION(toLong, makeConversionAlias("$toLong"_sd, BSONType::NumberLong));
-REGISTER_EXPRESSION(toDecimal, makeConversionAlias("$toDecimal"_sd, BSONType::NumberDecimal));
-REGISTER_EXPRESSION(toBool, makeConversionAlias("$toBool"_sd, BSONType::Bool));
+REGISTER_STABLE_EXPRESSION(toString, makeConversionAlias("$toString"_sd, BSONType::String));
+REGISTER_STABLE_EXPRESSION(toObjectId, makeConversionAlias("$toObjectId"_sd, BSONType::jstOID));
+REGISTER_STABLE_EXPRESSION(toDate, makeConversionAlias("$toDate"_sd, BSONType::Date));
+REGISTER_STABLE_EXPRESSION(toDouble, makeConversionAlias("$toDouble"_sd, BSONType::NumberDouble));
+REGISTER_STABLE_EXPRESSION(toInt, makeConversionAlias("$toInt"_sd, BSONType::NumberInt));
+REGISTER_STABLE_EXPRESSION(toLong, makeConversionAlias("$toLong"_sd, BSONType::NumberLong));
+REGISTER_STABLE_EXPRESSION(toDecimal,
+ makeConversionAlias("$toDecimal"_sd, BSONType::NumberDecimal));
+REGISTER_STABLE_EXPRESSION(toBool, makeConversionAlias("$toBool"_sd, BSONType::Bool));
boost::intrusive_ptr<Expression> ExpressionConvert::create(ExpressionContext* const expCtx,
boost::intrusive_ptr<Expression> input,
@@ -6724,7 +6740,7 @@ ExpressionRegex::getConstantPatternAndOptions() const {
/* -------------------------- ExpressionRegexFind ------------------------------ */
-REGISTER_EXPRESSION(regexFind, ExpressionRegexFind::parse);
+REGISTER_STABLE_EXPRESSION(regexFind, ExpressionRegexFind::parse);
boost::intrusive_ptr<Expression> ExpressionRegexFind::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -6744,7 +6760,7 @@ Value ExpressionRegexFind::evaluate(const Document& root, Variables* variables)
/* -------------------------- ExpressionRegexFindAll ------------------------------ */
-REGISTER_EXPRESSION(regexFindAll, ExpressionRegexFindAll::parse);
+REGISTER_STABLE_EXPRESSION(regexFindAll, ExpressionRegexFindAll::parse);
boost::intrusive_ptr<Expression> ExpressionRegexFindAll::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -6805,7 +6821,7 @@ Value ExpressionRegexFindAll::evaluate(const Document& root, Variables* variable
/* -------------------------- ExpressionRegexMatch ------------------------------ */
-REGISTER_EXPRESSION(regexMatch, ExpressionRegexMatch::parse);
+REGISTER_STABLE_EXPRESSION(regexMatch, ExpressionRegexMatch::parse);
boost::intrusive_ptr<Expression> ExpressionRegexMatch::parse(ExpressionContext* const expCtx,
BSONElement expr,
const VariablesParseState& vpsIn) {
@@ -6822,7 +6838,7 @@ Value ExpressionRegexMatch::evaluate(const Document& root, Variables* variables)
}
/* -------------------------- ExpressionRandom ------------------------------ */
-REGISTER_EXPRESSION(rand, ExpressionRandom::parse);
+REGISTER_STABLE_EXPRESSION(rand, ExpressionRandom::parse);
static thread_local PseudoRandom threadLocalRNG(SecureRandom().nextInt64());
@@ -6867,7 +6883,7 @@ Value ExpressionRandom::serialize(const bool explain) const {
}
/* ------------------------- ExpressionToHashedIndexKey -------------------------- */
-REGISTER_EXPRESSION(toHashedIndexKey, ExpressionToHashedIndexKey::parse);
+REGISTER_STABLE_EXPRESSION(toHashedIndexKey, ExpressionToHashedIndexKey::parse);
boost::intrusive_ptr<Expression> ExpressionToHashedIndexKey::parse(ExpressionContext* const expCtx,
BSONElement expr,
@@ -7008,6 +7024,8 @@ Value ExpressionDateArithmetics::evaluate(const Document& root, Variables* varia
REGISTER_EXPRESSION_WITH_MIN_VERSION(dateAdd,
ExpressionDateAdd::parse,
+ AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithClientType::kAny,
ServerGlobalParams::FeatureCompatibility::Version::kVersion49);
boost::intrusive_ptr<Expression> ExpressionDateAdd::parse(ExpressionContext* const expCtx,
@@ -7033,6 +7051,8 @@ Value ExpressionDateAdd::evaluateDateArithmetics(Date_t date,
REGISTER_EXPRESSION_WITH_MIN_VERSION(dateSubtract,
ExpressionDateSubtract::parse,
+ AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithClientType::kAny,
ServerGlobalParams::FeatureCompatibility::Version::kVersion49);
boost::intrusive_ptr<Expression> ExpressionDateSubtract::parse(ExpressionContext* const expCtx,
@@ -7061,6 +7081,8 @@ Value ExpressionDateSubtract::evaluateDateArithmetics(Date_t date,
// TODO SERVER-53028: make the expression to be available for any FCV when 5.0 becomes last-lts.
REGISTER_EXPRESSION_WITH_MIN_VERSION(dateTrunc,
ExpressionDateTrunc::parse,
+ AllowedWithApiStrict::kNeverInVersion1,
+ AllowedWithClientType::kAny,
ServerGlobalParams::FeatureCompatibility::Version::kVersion49);
ExpressionDateTrunc::ExpressionDateTrunc(ExpressionContext* const expCtx,
diff --git a/src/mongo/db/pipeline/expression.h b/src/mongo/db/pipeline/expression.h
index 64b7c053433..59c250b6c10 100644
--- a/src/mongo/db/pipeline/expression.h
+++ b/src/mongo/db/pipeline/expression.h
@@ -49,6 +49,7 @@
#include "mongo/db/pipeline/expression_visitor.h"
#include "mongo/db/pipeline/field_path.h"
#include "mongo/db/pipeline/variables.h"
+#include "mongo/db/query/allowed_contexts.h"
#include "mongo/db/query/datetime/date_time_support.h"
#include "mongo/db/query/query_feature_flags_gen.h"
#include "mongo/db/query/sort_pattern.h"
@@ -67,15 +68,20 @@ class DocumentSource;
* Registers a Parser so it can be called from parseExpression and friends.
*
* As an example, if your expression looks like {"$foo": [1,2,3]} you would add this line:
- * REGISTER_EXPRESSION(foo, ExpressionFoo::parse);
+ * REGISTER_STABLE_EXPRESSION(foo, ExpressionFoo::parse);
*
- * An expression registered this way can be used in any featureCompatibilityVersion.
+ * An expression registered this way can be used in any featureCompatibilityVersion and will be
+ * considered part of the stable API.
*/
-#define REGISTER_EXPRESSION(key, parser) \
+#define REGISTER_STABLE_EXPRESSION(key, parser) \
MONGO_INITIALIZER_GENERAL( \
addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
(InitializerContext*) { \
- Expression::registerExpression("$" #key, (parser), boost::none); \
+ Expression::registerExpression("$" #key, \
+ (parser), \
+ AllowedWithApiStrict::kAlways, \
+ AllowedWithClientType::kAny, \
+ boost::none); \
}
/**
@@ -86,44 +92,61 @@ class DocumentSource;
* feature_flags::gFoo and version >= X, you would add this line:
* REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION(
* foo, ExpressionFoo::parse, feature_flags::gFoo, X);
+ *
+ * Expressions registered in this way will not be included in the stable API.
*/
-#define REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION( \
- key, parser, featureFlag, minVersion) \
- MONGO_INITIALIZER_GENERAL( \
- addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
- (InitializerContext*) { \
- if (featureFlag.isEnabledAndIgnoreFCV()) { \
- Expression::registerExpression("$" #key, (parser), (minVersion)); \
- } \
+#define REGISTER_FEATURE_FLAG_GUARDED_EXPRESSION_WITH_MIN_VERSION( \
+ key, parser, featureFlag, minVersion) \
+ MONGO_INITIALIZER_GENERAL( \
+ addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
+ (InitializerContext*) { \
+ if (featureFlag.isEnabledAndIgnoreFCV()) { \
+ Expression::registerExpression("$" #key, \
+ (parser), \
+ AllowedWithApiStrict::kNeverInVersion1, \
+ AllowedWithClientType::kAny, \
+ (minVersion)); \
+ } \
}
/**
- * Registers a Parser so it can be called from parseExpression and friends. Use this version if your
- * expression can only be persisted to a catalog data structure in a feature compatibility version
+ * Registers a Parser so it can be called from parseExpression and friends. Use this version if
+ * your expression can only be persisted to a catalog data structure in a feature compatibility
+ * version
* >= X.
*
- * As an example, if your expression looks like {"$foo": [1,2,3]}, and can only be used in a feature
- * compatibility version >= X, you would add this line:
+ * As an example, if your expression looks like {"$foo": [1,2,3]}, and can only be used in a
+ * feature compatibility version >= X, you would add this line:
* REGISTER_EXPRESSION_WITH_MIN_VERSION(foo, ExpressionFoo::parse, X);
+ *
+ * If 'allowedWithApiStrict' is set to 'kSometimes', this expression is expected to register its
+ * own parser and enforce the 'sometimes' behavior during that invocation. No extra validation
+ * will be done here.
*/
-#define REGISTER_EXPRESSION_WITH_MIN_VERSION(key, parser, minVersion) \
- MONGO_INITIALIZER_GENERAL( \
- addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
- (InitializerContext*) { \
- Expression::registerExpression("$" #key, (parser), (minVersion)); \
+#define REGISTER_EXPRESSION_WITH_MIN_VERSION( \
+ key, parser, allowedWithApiStrict, allowedClientType, minVersion) \
+ MONGO_INITIALIZER_GENERAL( \
+ addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
+ (InitializerContext*) { \
+ Expression::registerExpression( \
+ "$" #key, (parser), (allowedWithApiStrict), (allowedClientType), (minVersion)); \
}
/**
- * Registers a Parser only if test commands are enabled. Use this if your expression is only used
- * for testing purposes.
+ * Registers a Parser only if test commands are enabled. Use this if your expression is only
+ * used for testing purposes.
+ *
+ * Such an expression will be excluded from the stable API and only allowed with an internal
+ * client.
*/
-#define REGISTER_TEST_EXPRESSION(key, parser) \
- MONGO_INITIALIZER_GENERAL( \
- addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
- (InitializerContext*) { \
- if (getTestCommandsEnabled()) { \
- Expression::registerExpression("$" #key, (parser), boost::none); \
- } \
+#define REGISTER_TEST_EXPRESSION(key, allowedWithApiStrict, allowedClientType, parser) \
+ MONGO_INITIALIZER_GENERAL( \
+ addToExpressionParserMap_##key, ("default"), ("expressionParserMap")) \
+ (InitializerContext*) { \
+ if (getTestCommandsEnabled()) { \
+ Expression::registerExpression( \
+ "$" #key, (parser), (allowedWithApiStrict), (allowedClientType), boost::none); \
+ } \
}
class Expression : public RefCountable {
@@ -290,6 +313,8 @@ public:
static void registerExpression(
std::string key,
Parser parser,
+ AllowedWithApiStrict allowedWithApiStrict,
+ AllowedWithClientType allowedWithClientType,
boost::optional<ServerGlobalParams::FeatureCompatibility::Version> requiredMinVersion);
const auto& getChildren() const {
diff --git a/src/mongo/db/pipeline/expression_function.cpp b/src/mongo/db/pipeline/expression_function.cpp
index e28acaca61b..c53b0004b31 100644
--- a/src/mongo/db/pipeline/expression_function.cpp
+++ b/src/mongo/db/pipeline/expression_function.cpp
@@ -31,7 +31,7 @@
namespace mongo {
-REGISTER_EXPRESSION(function, ExpressionFunction::parse);
+REGISTER_STABLE_EXPRESSION(function, ExpressionFunction::parse);
ExpressionFunction::ExpressionFunction(ExpressionContext* const expCtx,
boost::intrusive_ptr<Expression> passedArgs,
diff --git a/src/mongo/db/pipeline/expression_js_emit.cpp b/src/mongo/db/pipeline/expression_js_emit.cpp
index 44242fefcf3..d19a9c53191 100644
--- a/src/mongo/db/pipeline/expression_js_emit.cpp
+++ b/src/mongo/db/pipeline/expression_js_emit.cpp
@@ -36,7 +36,7 @@
namespace mongo {
-REGISTER_EXPRESSION(_internalJsEmit, ExpressionInternalJsEmit::parse);
+REGISTER_STABLE_EXPRESSION(_internalJsEmit, ExpressionInternalJsEmit::parse);
namespace {
/**
diff --git a/src/mongo/db/pipeline/expression_test_api_version.cpp b/src/mongo/db/pipeline/expression_test_api_version.cpp
index 7c77895bfff..3201ceada5e 100644
--- a/src/mongo/db/pipeline/expression_test_api_version.cpp
+++ b/src/mongo/db/pipeline/expression_test_api_version.cpp
@@ -33,7 +33,10 @@
namespace mongo {
-REGISTER_TEST_EXPRESSION(_testApiVersion, ExpressionTestApiVersion::parse);
+REGISTER_TEST_EXPRESSION(_testApiVersion,
+ AllowedWithApiStrict::kSometimes,
+ AllowedWithClientType::kAny,
+ ExpressionTestApiVersion::parse);
ExpressionTestApiVersion::ExpressionTestApiVersion(ExpressionContext* const expCtx,
bool unstable,
diff --git a/src/mongo/db/pipeline/expression_trigonometric.cpp b/src/mongo/db/pipeline/expression_trigonometric.cpp
index a97bc000ef7..06b63e16bcb 100644
--- a/src/mongo/db/pipeline/expression_trigonometric.cpp
+++ b/src/mongo/db/pipeline/expression_trigonometric.cpp
@@ -39,29 +39,29 @@ namespace mongo {
/**
* Inclusive Bounds
*/
-REGISTER_EXPRESSION(acos, ExpressionArcCosine::parse);
-REGISTER_EXPRESSION(asin, ExpressionArcSine::parse);
-REGISTER_EXPRESSION(atanh, ExpressionHyperbolicArcTangent::parse);
-REGISTER_EXPRESSION(acosh, ExpressionHyperbolicArcCosine::parse);
+REGISTER_STABLE_EXPRESSION(acos, ExpressionArcCosine::parse);
+REGISTER_STABLE_EXPRESSION(asin, ExpressionArcSine::parse);
+REGISTER_STABLE_EXPRESSION(atanh, ExpressionHyperbolicArcTangent::parse);
+REGISTER_STABLE_EXPRESSION(acosh, ExpressionHyperbolicArcCosine::parse);
/**
* Exclusive Bounds
*/
-REGISTER_EXPRESSION(cos, ExpressionCosine::parse);
-REGISTER_EXPRESSION(sin, ExpressionSine::parse);
-REGISTER_EXPRESSION(tan, ExpressionTangent::parse);
+REGISTER_STABLE_EXPRESSION(cos, ExpressionCosine::parse);
+REGISTER_STABLE_EXPRESSION(sin, ExpressionSine::parse);
+REGISTER_STABLE_EXPRESSION(tan, ExpressionTangent::parse);
/**
* Unbounded
*/
-REGISTER_EXPRESSION(atan, ExpressionArcTangent::parse);
-REGISTER_EXPRESSION(asinh, ExpressionHyperbolicArcSine::parse);
-REGISTER_EXPRESSION(cosh, ExpressionHyperbolicCosine::parse);
-REGISTER_EXPRESSION(sinh, ExpressionHyperbolicSine::parse);
-REGISTER_EXPRESSION(tanh, ExpressionHyperbolicTangent::parse);
+REGISTER_STABLE_EXPRESSION(atan, ExpressionArcTangent::parse);
+REGISTER_STABLE_EXPRESSION(asinh, ExpressionHyperbolicArcSine::parse);
+REGISTER_STABLE_EXPRESSION(cosh, ExpressionHyperbolicCosine::parse);
+REGISTER_STABLE_EXPRESSION(sinh, ExpressionHyperbolicSine::parse);
+REGISTER_STABLE_EXPRESSION(tanh, ExpressionHyperbolicTangent::parse);
-REGISTER_EXPRESSION(atan2, ExpressionArcTangent2::parse);
+REGISTER_STABLE_EXPRESSION(atan2, ExpressionArcTangent2::parse);
-REGISTER_EXPRESSION(degreesToRadians, ExpressionDegreesToRadians::parse);
-REGISTER_EXPRESSION(radiansToDegrees, ExpressionRadiansToDegrees::parse);
+REGISTER_STABLE_EXPRESSION(degreesToRadians, ExpressionDegreesToRadians::parse);
+REGISTER_STABLE_EXPRESSION(radiansToDegrees, ExpressionRadiansToDegrees::parse);
} // namespace mongo
diff --git a/src/mongo/db/pipeline/lite_parsed_document_source.h b/src/mongo/db/pipeline/lite_parsed_document_source.h
index ceb33521bcc..3c2ab7d2772 100644
--- a/src/mongo/db/pipeline/lite_parsed_document_source.h
+++ b/src/mongo/db/pipeline/lite_parsed_document_source.h
@@ -38,6 +38,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/commands/server_status_metric.h"
#include "mongo/db/namespace_string.h"
+#include "mongo/db/query/allowed_contexts.h"
#include "mongo/db/read_concern_support_result.h"
#include "mongo/db/repl/read_concern_args.h"
#include "mongo/stdx/unordered_set.h"
@@ -54,32 +55,6 @@ class LiteParsedPipeline;
*/
class LiteParsedDocumentSource {
public:
- /**
- * Flags to mark stages with different allowance constrains when API versioning is enabled.
- */
- enum class AllowedWithApiStrict {
- // The stage is always allowed in the pipeline regardless of API versions.
- kAlways,
- // This stage can be allowed in a stable API version, depending on the parameters.
- kSometimes,
- // The stage is allowed only for internal client when 'apiStrict' is set to true.
- kInternal,
- // The stage is never allowed in API version '1' when 'apiStrict' is set to true.
- kNeverInVersion1
- };
-
- /**
- * Determines the type of client which is permitted to use a particular stage in its command
- * request. Ensures that only internal clients are permitted to send or deserialize certain
- * stages.
- */
- enum class AllowedWithClientType {
- // The stage can be specified in the command request of any client.
- kAny,
- // The stage can be specified in the command request of an internal client only.
- kInternal,
- };
-
/*
* This is the type of parser you should register using REGISTER_DOCUMENT_SOURCE. It need not
* do any validation of options, only enough parsing to be able to implement the interface.
diff --git a/src/mongo/db/pipeline/lite_parsed_pipeline.cpp b/src/mongo/db/pipeline/lite_parsed_pipeline.cpp
index 437c7d17f5c..6c25f38573c 100644
--- a/src/mongo/db/pipeline/lite_parsed_pipeline.cpp
+++ b/src/mongo/db/pipeline/lite_parsed_pipeline.cpp
@@ -128,58 +128,27 @@ void LiteParsedPipeline::tickGlobalStageCounters() const {
void LiteParsedPipeline::validate(const OperationContext* opCtx,
bool performApiVersionChecks) const {
- // An internal client could be one of the following :
- // - Does not have any transport session
- // - The transport session tag is internal
- auto client = opCtx->getClient();
- const auto isInternalClient =
- !client->session() || (client->session()->getTags() & transport::Session::kInternalClient);
-
- const auto apiParameters = APIParameters::get(opCtx);
- auto apiVersion = apiParameters.getAPIVersion().value_or("");
- auto apiStrict = apiParameters.getAPIStrict().value_or(false);
- using AllowanceFlags = LiteParsedDocumentSource::AllowedWithApiStrict;
int internalUnpackBucketCount = 0;
for (auto&& stage : _stageSpecs) {
const auto& stageName = stage->getParseTimeName();
const auto& stageInfo = LiteParsedDocumentSource::getInfo(stageName);
- uassert(5491300,
- str::stream() << "The stage '" << stageName << "' is not allowed in user requests",
- !(stageInfo.allowedWithClientType ==
- LiteParsedDocumentSource::AllowedWithClientType::kInternal &&
- !isInternalClient));
-
// Validate that the stage is API version compatible.
- if (performApiVersionChecks && apiStrict) {
- switch (stageInfo.allowedWithApiStrict) {
- case AllowanceFlags::kNeverInVersion1: {
- uassert(ErrorCodes::APIStrictError,
- str::stream()
- << "stage " << stageName
- << " is not allowed with 'apiStrict: true' in API Version "
- << apiVersion,
- apiVersion != "1");
- break;
- }
- case AllowanceFlags::kInternal: {
- uassert(ErrorCodes::APIStrictError,
- str::stream()
- << "Internal stage " << stageName
- << " cannot be specified with 'apiStrict: true' in API Version "
- << apiVersion,
- isInternalClient);
- break;
- }
- case AllowanceFlags::kSometimes: {
+ if (performApiVersionChecks) {
+
+ std::function<void(const APIParameters&)> sometimesCallback =
+ [&](const APIParameters& apiParameters) {
+ tassert(5807600,
+ "Expected callback only if allowed 'sometimes'",
+ stageInfo.allowedWithApiStrict == AllowedWithApiStrict::kSometimes);
stage->assertPermittedInAPIVersion(apiParameters);
- break;
- }
- case AllowanceFlags::kAlways: {
- break;
- }
- }
+ };
+ assertLanguageFeatureIsAllowed(opCtx,
+ stageName,
+ stageInfo.allowedWithApiStrict,
+ stageInfo.allowedWithClientType,
+ sometimesCallback);
}
internalUnpackBucketCount +=
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 7c5b7ad2e25..265ceed9445 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -113,8 +113,8 @@ env.Library(
"$BUILD_DIR/mongo/util/fail_point",
"collation/collator_factory_icu",
"collation/collator_icu",
+ "common_query_enums_and_helpers",
"datetime/init_timezone_data",
- "explain_options",
"query_planner",
"query_request",
],
@@ -124,15 +124,20 @@ env.Library(
)
env.Library(
- target="explain_options",
+ target="common_query_enums_and_helpers",
source=[
+ "allowed_contexts.cpp",
"explain_options.cpp",
"explain_verbosity.idl"
],
LIBDEPS=[
"$BUILD_DIR/mongo/base",
+ "$BUILD_DIR/mongo/db/api_parameters",
"$BUILD_DIR/mongo/idl/idl_parser",
],
+ LIBDEPS_PRIVATE=[
+ "$BUILD_DIR/mongo/transport/transport_layer_common",
+ ],
)
env.Library(
@@ -373,7 +378,7 @@ env.CppUnitTest(
"collation/collator_factory_mock",
"collation/collator_interface_mock",
"command_request_response",
- "explain_options",
+ "common_query_enums_and_helpers",
"hint_parser",
"map_reduce_output_format",
"query_common",
diff --git a/src/mongo/db/query/allowed_contexts.cpp b/src/mongo/db/query/allowed_contexts.cpp
new file mode 100644
index 00000000000..1a2eebadc7f
--- /dev/null
+++ b/src/mongo/db/query/allowed_contexts.cpp
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/query/allowed_contexts.h"
+
+#include "mongo/transport/session.h"
+
+namespace mongo {
+
+void assertLanguageFeatureIsAllowed(
+ const OperationContext* opCtx,
+ std::string operatorName,
+ AllowedWithApiStrict allowedWithApiStrict,
+ AllowedWithClientType allowedWithClientType,
+ boost::optional<std::function<void(const APIParameters&)>> callbackForSometimesAllowed) {
+ // An internal client could be one of the following :
+ // - Does not have any transport session
+ // - The transport session tag is internal
+ auto client = opCtx->getClient();
+ const auto isInternalClient = client &&
+ (!client->session() ||
+ (client->session()->getTags() & transport::Session::kInternalClient));
+
+ const auto apiParameters = APIParameters::get(opCtx);
+
+ uassert(5491300,
+ str::stream() << operatorName << "' is not allowed in user requests",
+ !(allowedWithClientType == AllowedWithClientType::kInternal && !isInternalClient));
+
+ const auto apiVersion = apiParameters.getAPIVersion().value_or("");
+ const auto apiStrict = apiParameters.getAPIStrict().value_or(false);
+ if (!apiStrict) {
+ return;
+ }
+ switch (allowedWithApiStrict) {
+ case AllowedWithApiStrict::kNeverInVersion1: {
+ uassert(ErrorCodes::APIStrictError,
+ str::stream() << operatorName
+ << " is not allowed with 'apiStrict: true' in API Version "
+ << apiVersion,
+ apiVersion != "1");
+ break;
+ }
+ case AllowedWithApiStrict::kInternal: {
+ uassert(ErrorCodes::APIStrictError,
+ str::stream() << operatorName
+ << " cannot be specified with 'apiStrict: true' in API Version "
+ << apiVersion,
+ isInternalClient);
+ break;
+ }
+ case AllowedWithApiStrict::kSometimes: {
+ if (auto callback = callbackForSometimesAllowed) {
+ (*callback)(apiParameters);
+ }
+ break;
+ }
+ case AllowedWithApiStrict::kAlways: {
+ break;
+ }
+ }
+}
+} // namespace mongo
diff --git a/src/mongo/db/query/allowed_contexts.h b/src/mongo/db/query/allowed_contexts.h
new file mode 100644
index 00000000000..a8c1506d749
--- /dev/null
+++ b/src/mongo/db/query/allowed_contexts.h
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2021-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/base/status.h"
+#include "mongo/db/api_parameters.h"
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+/**
+ * Flags to mark language features with different allowance constraints when API versioning is
+ * enabled.
+ */
+enum class AllowedWithApiStrict {
+ // The stage is always allowed in the pipeline regardless of API versions.
+ kAlways,
+ // This stage can be allowed in a stable API version, depending on the parameters.
+ kSometimes,
+ // The stage is allowed only for internal client when 'apiStrict' is set to true.
+ kInternal,
+ // The stage is never allowed in API version '1' when 'apiStrict' is set to true.
+ kNeverInVersion1
+};
+
+/**
+ * Determines the type of client which is permitted to use a particular stage in its command
+ * request. Ensures that only internal clients are permitted to send or deserialize certain
+ * stages.
+ */
+enum class AllowedWithClientType {
+ // The stage can be specified in the command request of any client.
+ kAny,
+ // The stage can be specified in the command request of an internal client only.
+ kInternal,
+};
+
+/**
+ * Asserts that the API parameters in 'apiParameters' are compatible with the restrictions on
+ * 'operatorName' given by 'allowedWithApiStrict' and 'allowedWithClientType'. If the operator is
+ * allowed 'sometimes', a callback can be provided in 'callbackForSometimesAllowed' to check if the
+ * conditions are met.
+ */
+void assertLanguageFeatureIsAllowed(const OperationContext* opCtx,
+ std::string operatorName,
+ AllowedWithApiStrict allowedWithApiStrict,
+ AllowedWithClientType allowedWithClientType,
+ boost::optional<std::function<void(const APIParameters&)>>
+ callbackForSometimesAllowed = boost::none);
+
+} // namespace mongo
diff --git a/src/mongo/s/query/document_source_merge_cursors.cpp b/src/mongo/s/query/document_source_merge_cursors.cpp
index 737ad721006..0472e3d0a54 100644
--- a/src/mongo/s/query/document_source_merge_cursors.cpp
+++ b/src/mongo/s/query/document_source_merge_cursors.cpp
@@ -41,7 +41,7 @@ namespace mongo {
REGISTER_DOCUMENT_SOURCE(mergeCursors,
LiteParsedDocumentSourceDefault::parse,
DocumentSourceMergeCursors::createFromBson,
- LiteParsedDocumentSource::AllowedWithApiStrict::kInternal);
+ AllowedWithApiStrict::kInternal);
constexpr StringData DocumentSourceMergeCursors::kStageName;