diff options
28 files changed, 280 insertions, 60 deletions
diff --git a/buildscripts/idl/idl/ast.py b/buildscripts/idl/idl/ast.py index a07d547248e..a3808963213 100644 --- a/buildscripts/idl/idl/ast.py +++ b/buildscripts/idl/idl/ast.py @@ -109,6 +109,9 @@ class Type(common.SourceLocation): self.first_element_field_name = None # type: str self.deserialize_with_tenant = False # type: bool self.internal_only = False # type: bool + # Marks whether this type is a query shape component. + # Can only be true if is_struct is true. + self.is_query_shape_component = False # type: bool super(Type, self).__init__(file_name, line, column) @@ -251,14 +254,14 @@ class Field(common.SourceLocation): # See WRITING-13831 for details on query shape. self.query_shape_literal = None # type: Optional[bool] # Determines whether or not this field represents a fieldpath that should be anonymized. - self.query_shape_fieldpath = None # type: Optional[bool] + self.query_shape_anonymize = None # type: Optional[bool] super(Field, self).__init__(file_name, line, column) @property def should_serialize_query_shape(self): # type: () -> bool - return self.query_shape_fieldpath or self.query_shape_literal + return self.query_shape_anonymize or self.query_shape_literal class Privilege(common.SourceLocation): diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index da4191d83fc..179768e6df1 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -327,17 +327,17 @@ def _bind_struct_common(ctxt, parsed_spec, struct, ast_struct): # Verify that each field on the struct defines a query shape type on the field if and only if # query_shape_component is defined on the struct. - defined_query_shape_type = ast_field.query_shape_literal is not None or ast_field.query_shape_fieldpath is not None + defined_query_shape_type = ast_field.query_shape_literal is not None or ast_field.query_shape_anonymize is not None if not field.hidden and struct.query_shape_component and not defined_query_shape_type: ctxt.add_must_declare_shape_type(ast_field, ast_struct.name, ast_field.name) if not struct.query_shape_component and defined_query_shape_type: ctxt.add_must_be_query_shape_component(ast_field, ast_struct.name, ast_field.name) - if ast_field.query_shape_fieldpath and ast_field.type.cpp_type not in [ + if ast_field.query_shape_anonymize and ast_field.type.cpp_type not in [ "std::string", "std::vector<std::string>" ]: - ctxt.add_query_shape_fieldpath_must_be_string(ast_field, ast_field.name, + ctxt.add_query_shape_anonymize_must_be_string(ast_field, ast_field.name, ast_field.type.cpp_type) # Fill out the field comparison_order property as needed @@ -455,6 +455,7 @@ def _bind_struct_type(struct): ast_type.cpp_type = _get_struct_qualified_cpp_name(struct) ast_type.bson_serialization_type = ["object"] ast_type.first_element_field_name = struct.fields[0].name if struct.fields else None + ast_type.is_query_shape_component = struct.query_shape_component return ast_type @@ -1019,6 +1020,7 @@ def _bind_type(idltype): ast_type.deserializer = _normalize_method_name(idltype.cpp_type, idltype.deserializer) ast_type.deserialize_with_tenant = idltype.deserialize_with_tenant ast_type.internal_only = idltype.internal_only + ast_type.is_query_shape_component = True return ast_type @@ -1045,7 +1047,7 @@ def _bind_field(ctxt, parsed_spec, field): ast_field.always_serialize = field.always_serialize ast_field.preparse = field.preparse ast_field.query_shape_literal = field.query_shape_literal - ast_field.query_shape_fieldpath = field.query_shape_fieldpath + ast_field.query_shape_anonymize = field.query_shape_anonymize ast_field.cpp_name = field.name if field.cpp_name: @@ -1056,11 +1058,11 @@ def _bind_field(ctxt, parsed_spec, field): ctxt.add_array_not_valid_error(ast_field, "field", ast_field.name) # Validate that 'field' is not both a query shape literal and query shape fieldpath. The two are mutually exclusive. - if ast_field.query_shape_literal is not None and ast_field.query_shape_fieldpath is not None: + if ast_field.query_shape_literal is not None and ast_field.query_shape_anonymize is not None: ctxt.add_field_cannot_be_literal_and_fieldpath(ast_field, ast_field.name) - if ast_field.query_shape_fieldpath is False: - ctxt.add_field_cannot_have_query_shape_fieldpath_false(ast_field) + if ast_field.query_shape_anonymize is False: + ctxt.add_field_cannot_have_query_shape_anonymize_false(ast_field) if field.ignore: ast_field.ignore = field.ignore @@ -1134,6 +1136,8 @@ def _bind_field(ctxt, parsed_spec, field): if ast_field.validator is None: return None + if ast_field.should_serialize_query_shape and not ast_field.type.is_query_shape_component: + ctxt.add_must_be_query_shape_component(ast_field, ast_field.type.name, ast_field.name) return ast_field diff --git a/buildscripts/idl/idl/errors.py b/buildscripts/idl/idl/errors.py index e9386535ffe..5837cb11648 100644 --- a/buildscripts/idl/idl/errors.py +++ b/buildscripts/idl/idl/errors.py @@ -950,10 +950,10 @@ class ParserContext(object): def add_must_declare_shape_type(self, location, struct_name, field_name): # type: (common.SourceLocation, str, str) -> None - """Add an error about a field not specifying either query_shape_literal or query_shape_fieldpath if the struct is query_shape_component.""" + """Add an error about a field not specifying either query_shape_literal or query_shape_anonymize if the struct is query_shape_component.""" self._add_error( location, ERROR_ID_FIELD_MUST_DECLARE_SHAPE_LITERAL, - f"Field '{field_name}' must specify either 'query_shape_literal' or 'query_shape_fieldpath' since struct '{struct_name}' is a query shape component." + f"Field '{field_name}' must specify either 'query_shape_literal' or 'query_shape_anonymize' since struct '{struct_name}' is a query shape component." ) def add_must_be_query_shape_component(self, location, struct_name, field_name): @@ -963,7 +963,7 @@ class ParserContext(object): f"Field '{field_name}' cannot specify 'query_shape_literal' property since struct '{struct_name}' is not a query shape component." ) - def add_query_shape_fieldpath_must_be_string(self, location, field_name, field_type): + def add_query_shape_anonymize_must_be_string(self, location, field_name, field_type): self._add_error( location, ERROR_ID_INVALID_TYPE_FOR_SHAPIFY, f"In order for {field_name} to be marked as a query shape fieldpath, it must have a string type, not {field_type}." @@ -975,9 +975,9 @@ class ParserContext(object): f"{field_name} cannot be marked as both a query shape literal and query shape fieldpath." ) - def add_field_cannot_have_query_shape_fieldpath_false(self, location): + def add_field_cannot_have_query_shape_anonymize_false(self, location): self._add_error(location, ERROR_ID_QUERY_SHAPE_FIELDPATH_CANNOT_BE_FALSE, - "'query_shape_fieldpath' cannot be defined as false if it is set.") + "'query_shape_anonymize' cannot be defined as false if it is set.") def _assert_unique_error_messages(): diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index b472ffe17a6..26792609546 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -2166,7 +2166,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(${expression}).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'builder->append(${field_name}, options.serializeFieldPathFromString(${expression}));' ) @@ -2321,7 +2321,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(${expression}).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'builder->append(${field_name}, options.serializeFieldPathFromString(${expression}));' ) @@ -2335,7 +2335,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(value).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'idl::idlSerialize(builder, ${field_name}, options.serializeFieldPathFromString(value));' ) @@ -2382,7 +2382,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_line( 'options.serializeLiteralValue(%s).serializeForIDL(%s, builder);' % (_access_member(field), _get_field_constant_name(field))) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_line( 'builder->append(%s, options.serializeFieldPathFromString(%s));' % (_get_field_constant_name(field), _access_member(field))) diff --git a/buildscripts/idl/idl/parser.py b/buildscripts/idl/idl/parser.py index cc4f047231e..022ad0dd3f9 100644 --- a/buildscripts/idl/idl/parser.py +++ b/buildscripts/idl/idl/parser.py @@ -408,7 +408,7 @@ def _parse_field(ctxt, name, node): _RuleDesc('bool_scalar'), "query_shape_literal": _RuleDesc('required_bool_scalar'), - "query_shape_fieldpath": + "query_shape_anonymize": _RuleDesc('required_bool_scalar'), }) diff --git a/buildscripts/idl/idl/syntax.py b/buildscripts/idl/idl/syntax.py index c8b3573294f..f161488062e 100644 --- a/buildscripts/idl/idl/syntax.py +++ b/buildscripts/idl/idl/syntax.py @@ -494,7 +494,7 @@ class Field(common.SourceLocation): self.constructed = False # type: bool self.query_shape_literal = None # type: Optional[bool] - self.query_shape_fieldpath = None # type: Optional[bool] + self.query_shape_anonymize = None # type: Optional[bool] self.hidden = False # type: bool diff --git a/buildscripts/idl/tests/test_binder.py b/buildscripts/idl/tests/test_binder.py index a891c6f15b2..c4e3c806d71 100644 --- a/buildscripts/idl/tests/test_binder.py +++ b/buildscripts/idl/tests/test_binder.py @@ -2704,7 +2704,7 @@ class TestBinder(testcase.IDLTestcase): query_shape_literal: false """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) - # Validating query_shape_fieldpath relies on std::string + # Validating query_shape_anonymize relies on std::string basic_types = textwrap.dedent(""" types: string: @@ -2731,7 +2731,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: string field2: query_shape_literal: false @@ -2746,7 +2746,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: array<string> field2: query_shape_literal: false @@ -2762,7 +2762,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: false + query_shape_anonymize: false type: string field2: query_shape_literal: false @@ -2778,7 +2778,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: bool field2: query_shape_literal: false @@ -2794,7 +2794,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: array<bool> field2: query_shape_literal: false @@ -2810,7 +2810,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true query_shape_literal: true type: string field2: @@ -2818,6 +2818,38 @@ class TestBinder(testcase.IDLTestcase): type: bool """), idl.errors.ERROR_ID_CANNOT_BE_LITERAL_AND_FIELDPATH) + self.assert_bind_fail( + basic_types + textwrap.dedent(""" + structs: + StructZero: + strict: true + description: "" + fields: + field1: + query_shape_literal: true + type: string + """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) + + self.assert_bind_fail( + basic_types + textwrap.dedent(""" + structs: + StructZero: + strict: true + description: "" + fields: + field1: + type: string + struct1: + query_shape_component: true + strict: true + description: "" + fields: + field2: + type: StructZero + description: "" + query_shape_literal: true + """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) + if __name__ == '__main__': diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 29ba3357afd..82737ca855e 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1609,7 +1609,6 @@ env.Library( 'pipeline/make_js_function.cpp', 'pipeline/monotonic_expression.cpp', 'pipeline/variables.cpp', - 'query/serialization_options.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/bson/util/bson_extract', @@ -1635,6 +1634,7 @@ env.Library( 'query/collation/collator_interface', 'query/datetime/date_time_support', 'query/query_knobs', + 'serialization_options', 'stats/counters', 'update/pattern_cmp', ], @@ -1647,6 +1647,19 @@ env.Library( ) env.Library( + target='serialization_options', + source=[ + 'query/serialization_options.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/exec/document_value/document_value', + '$BUILD_DIR/mongo/db/pipeline/field_path', + ], + LIBDEPS_PRIVATE=[], +) + +env.Library( target='startup_recovery', source=[ 'repair.cpp', diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index d20c1f0f99c..75bbde6b153 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -496,6 +496,7 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/exec/document_value/document_value', + '$BUILD_DIR/mongo/db/serialization_options', '$BUILD_DIR/mongo/db/storage/key_string', '$BUILD_DIR/mongo/idl/idl_parser', '$BUILD_DIR/mongo/s/common_s', @@ -593,6 +594,7 @@ env.CppUnitTest( 'document_source_change_stream_add_post_image_test.cpp', 'document_source_change_stream_test.cpp', 'document_source_check_resume_token_test.cpp', + 'document_source_coll_stats_test.cpp', 'document_source_count_test.cpp', 'document_source_current_op_test.cpp', 'document_source_densify_test.cpp', diff --git a/src/mongo/db/pipeline/document_source_coll_stats.cpp b/src/mongo/db/pipeline/document_source_coll_stats.cpp index 96fd6d1c48a..0facc2283ef 100644 --- a/src/mongo/db/pipeline/document_source_coll_stats.cpp +++ b/src/mongo/db/pipeline/document_source_coll_stats.cpp @@ -132,10 +132,7 @@ DocumentSource::GetNextResult DocumentSourceCollStats::doGetNext() { } Value DocumentSourceCollStats::serialize(SerializationOptions opts) const { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484352); - } - return Value(Document{{getSourceName(), _collStatsSpec.toBSON()}}); + return Value(Document{{getSourceName(), _collStatsSpec.toBSON(opts)}}); } } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_coll_stats.idl b/src/mongo/db/pipeline/document_source_coll_stats.idl index 18efd4d2c7f..0f146db02cf 100644 --- a/src/mongo/db/pipeline/document_source_coll_stats.idl +++ b/src/mongo/db/pipeline/document_source_coll_stats.idl @@ -39,36 +39,46 @@ structs: LatencyStatsSpec: description: Represents the 'latencyStats' argument to the $collStats stage. strict: true - fields: + query_shape_component: true + fields: histograms: description: Adds latency histogram information to the embedded documents in latencyStats if true. type: optionalBool + # Do not abstract this literal, since it is parameterizing the stage like an enum rather than representing + # real user input. + query_shape_literal: false DocumentSourceCollStatsSpec: description: Specification for a $collStats stage. strict: true + query_shape_component: true fields: latencyStats: description: A request to include latency stats in the $collStats output. type: LatencyStatsSpec optional: true + query_shape_literal: true storageStats: description: Adds storage statistics to the return document. type: StorageStatsSpec optional: true + query_shape_literal: true count: description: Adds the total number of documents in the collection to the return document. type: object validator: callback: validateObjectIsEmpty optional: true + query_shape_literal: true queryExecStats: description: Adds query execution statistics to the return document. type: object validator: callback: validateObjectIsEmpty optional: true + query_shape_literal: true $_requestOnTimeseriesView: description: When set to true, $collStats stage requests statistics from the view namespace. When set to false, $collStats stage requests statistics from the underlying collection. cpp_name: requestOnTimeseriesView type: optionalBool + query_shape_literal: false diff --git a/src/mongo/db/pipeline/document_source_coll_stats_test.cpp b/src/mongo/db/pipeline/document_source_coll_stats_test.cpp new file mode 100644 index 00000000000..87b7473b47a --- /dev/null +++ b/src/mongo/db/pipeline/document_source_coll_stats_test.cpp @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2023-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/db/pipeline/aggregation_context_fixture.h" +#include "mongo/db/pipeline/document_source_coll_stats.h" +#include "mongo/db/pipeline/document_source_coll_stats_gen.h" +#include "mongo/db/pipeline/expression_context_for_test.h" +#include "mongo/unittest/bson_test_util.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { +using DocumentSourceCollStatsTest = AggregationContextFixture; +TEST_F(DocumentSourceCollStatsTest, QueryShape) { + auto spec = DocumentSourceCollStatsSpec(); + + auto stage = make_intrusive<DocumentSourceCollStats>(getExpCtx(), spec); + ASSERT_BSONOBJ_EQ_AUTO( // NOLINT + R"({"$collStats":{}})", + redact(*stage)); + + spec.setCount(BSONObj()); + spec.setQueryExecStats(BSONObj()); + stage = make_intrusive<DocumentSourceCollStats>(getExpCtx(), spec); + ASSERT_BSONOBJ_EQ_AUTO( // NOLINT + R"({"$collStats":{"count":"?","queryExecStats":"?"}})", + redact(*stage)); + + auto latencyStats = LatencyStatsSpec(); + latencyStats.setHistograms(true); + spec.setLatencyStats(latencyStats); + stage = make_intrusive<DocumentSourceCollStats>(getExpCtx(), spec); + ASSERT_BSONOBJ_EQ_AUTO( // NOLINT + R"({ + "$collStats": { + "latencyStats": { + "histograms": true + }, + "count": "?", + "queryExecStats": "?" + } + })", + redact(*stage)); + + auto storageStats = StorageStatsSpec(); + storageStats.setScale(2); + storageStats.setVerbose(true); + spec.setStorageStats(storageStats); + stage = make_intrusive<DocumentSourceCollStats>(getExpCtx(), spec); + ASSERT_BSONOBJ_EQ_AUTO( // NOLINT + R"({ + "$collStats": { + "latencyStats": { + "histograms": true + }, + "storageStats": { + "scale": "?", + "verbose": true, + "waitForLock": true, + "numericOnly": false + }, + "count": "?", + "queryExecStats": "?" + } + })", + redact(*stage)); + + storageStats.setWaitForLock(false); + storageStats.setNumericOnly(false); + spec.setStorageStats(storageStats); + stage = make_intrusive<DocumentSourceCollStats>(getExpCtx(), spec); + ASSERT_BSONOBJ_EQ_AUTO( // NOLINT + R"({ + "$collStats": { + "latencyStats": { + "histograms": true + }, + "storageStats": { + "scale": "?", + "verbose": true, + "waitForLock": false, + "numericOnly": false + }, + "count": "?", + "queryExecStats": "?" + } + })", + redact(*stage)); +} +} // namespace +} // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_exchange.cpp b/src/mongo/db/pipeline/document_source_exchange.cpp index 2d6999f4a7d..81d7beecf64 100644 --- a/src/mongo/db/pipeline/document_source_exchange.cpp +++ b/src/mongo/db/pipeline/document_source_exchange.cpp @@ -94,10 +94,7 @@ const char* DocumentSourceExchange::getSourceName() const { } Value DocumentSourceExchange::serialize(SerializationOptions opts) const { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484348); - } - return Value(DOC(getSourceName() << _exchange->getSpec().toBSON())); + return Value(DOC(getSourceName() << _exchange->getSpec().toBSON(opts))); } DocumentSourceExchange::DocumentSourceExchange( diff --git a/src/mongo/db/pipeline/document_source_exchange_test.cpp b/src/mongo/db/pipeline/document_source_exchange_test.cpp index 6063c252dbd..a454dd283fe 100644 --- a/src/mongo/db/pipeline/document_source_exchange_test.cpp +++ b/src/mongo/db/pipeline/document_source_exchange_test.cpp @@ -749,4 +749,30 @@ TEST_F(DocumentSourceExchangeTest, RejectInvalidMissingKeys) { Exchange(parseSpec(spec), Pipeline::create({}, getExpCtx())), AssertionException, 50967); } +TEST_F(DocumentSourceExchangeTest, QueryShape) { + const size_t nDocs = 500; + + auto source = getMockSource(nDocs); + + ExchangeSpec spec; + spec.setPolicy(ExchangePolicyEnum::kRoundRobin); + spec.setConsumers(1); + spec.setBufferSize(1024); + boost::intrusive_ptr<Exchange> ex = new Exchange(spec, Pipeline::create({source}, getExpCtx())); + boost::intrusive_ptr<DocumentSourceExchange> stage = + new DocumentSourceExchange(getExpCtx(), ex, 0, nullptr); + + ASSERT_BSONOBJ_EQ_AUTO( // + R"({ + "$_internalExchange": { + "policy": "roundrobin", + "consumers": "?", + "orderPreserving": false, + "bufferSize": "?", + "key": "?" + } + })", + redact(*stage)); +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp index 5eb4e7625aa..38ba92a7a01 100644 --- a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp +++ b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.cpp @@ -129,12 +129,9 @@ Pipeline::SourceContainer::iterator DocumentSourceInternalAllCollectionStats::do void DocumentSourceInternalAllCollectionStats::serializeToArray(std::vector<Value>& array, SerializationOptions opts) const { auto explain = opts.verbosity; - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484341); - } if (explain) { BSONObjBuilder bob; - _internalAllCollectionStatsSpec.serialize(&bob); + _internalAllCollectionStatsSpec.serialize(&bob, opts); if (_absorbedMatch) { bob.append("match", _absorbedMatch->getQuery()); } @@ -170,9 +167,6 @@ const char* DocumentSourceInternalAllCollectionStats::getSourceName() const { } Value DocumentSourceInternalAllCollectionStats::serialize(SerializationOptions opts) const { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484340); - } - return Value(Document{{getSourceName(), _internalAllCollectionStatsSpec.toBSON()}}); + return Value(Document{{getSourceName(), _internalAllCollectionStatsSpec.toBSON(opts)}}); } } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.idl b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.idl index bb02e8b1954..8c3c43e637d 100644 --- a/src/mongo/db/pipeline/document_source_internal_all_collection_stats.idl +++ b/src/mongo/db/pipeline/document_source_internal_all_collection_stats.idl @@ -40,8 +40,10 @@ structs: DocumentSourceInternalAllCollectionStatsSpec: description: Specification for an $_internalAllCollectionStats stage. strict: true + query_shape_component: true fields: stats: description: Specification for a $collStats stage. type: DocumentSourceCollStatsSpec optional: true + query_shape_literal: true diff --git a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h index d86611ac874..2603db75aae 100644 --- a/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h +++ b/src/mongo/db/pipeline/document_source_list_cached_and_active_users.h @@ -88,9 +88,6 @@ public: } Value serialize(SerializationOptions opts = SerializationOptions()) const final override { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484330); - } return Value(Document{{getSourceName(), Document{}}}); } diff --git a/src/mongo/db/pipeline/document_source_list_local_sessions.h b/src/mongo/db/pipeline/document_source_list_local_sessions.h index 1244c2fa0ff..a9f258113da 100644 --- a/src/mongo/db/pipeline/document_source_list_local_sessions.h +++ b/src/mongo/db/pipeline/document_source_list_local_sessions.h @@ -102,10 +102,7 @@ public: } Value serialize(SerializationOptions opts = SerializationOptions()) const final override { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484328); - } - return Value(Document{{getSourceName(), _spec.toBSON()}}); + return Value(Document{{getSourceName(), _spec.toBSON(opts)}}); } StageConstraints constraints(Pipeline::SplitState pipeState) const final { diff --git a/src/mongo/db/pipeline/document_source_list_sessions.cpp b/src/mongo/db/pipeline/document_source_list_sessions.cpp index d8a0ca3fe91..6eb4fdf2819 100644 --- a/src/mongo/db/pipeline/document_source_list_sessions.cpp +++ b/src/mongo/db/pipeline/document_source_list_sessions.cpp @@ -75,14 +75,11 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceListSessions::createFromBson( } Value DocumentSourceListSessions::serialize(SerializationOptions opts) const { - if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { - MONGO_UNIMPLEMENTED_TASSERT(7484327); - } ListSessionsSpec spec; spec.setAllUsers(_allUsers); spec.setUsers(_users); spec.setPredicate(_predicate); - return Value(Document{{getSourceName(), spec.toBSON()}}); + return Value(Document{{getSourceName(), spec.toBSON(opts)}}); } } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_list_sessions.idl b/src/mongo/db/pipeline/document_source_list_sessions.idl index e919fbda2bd..5fcdeb000d4 100644 --- a/src/mongo/db/pipeline/document_source_list_sessions.idl +++ b/src/mongo/db/pipeline/document_source_list_sessions.idl @@ -40,21 +40,31 @@ structs: description: "A struct representing a $listSessions/$listLocalSessions User" strict: true generate_comparison_operators: true + query_shape_component: true fields: - user: string - db: string + user: + type: string + query_shape_anonymize: true + db: + type: string + query_shape_anonymize: true ListSessionsSpec: description: "$listSessions and $listLocalSessions pipeline spec" strict: true + query_shape_component: true fields: allUsers: type: bool default: false + # This boolean parameterizes the stage rather than representing user input, so do not abstract the literal. + query_shape_literal: false users: type: array<ListSessionsUser> optional: true + query_shape_literal: true $_internalPredicate: cpp_name: predicate type: object optional: true + query_shape_literal: true # This is a MatchExpression predicate and could be shape-ified rather than completely abstracted. diff --git a/src/mongo/db/pipeline/document_source_merge.cpp b/src/mongo/db/pipeline/document_source_merge.cpp index f30b330d0cd..6cb337d73ae 100644 --- a/src/mongo/db/pipeline/document_source_merge.cpp +++ b/src/mongo/db/pipeline/document_source_merge.cpp @@ -536,6 +536,7 @@ boost::optional<DocumentSource::DistributedPlanLogic> DocumentSourceMerge::distr Value DocumentSourceMerge::serialize(SerializationOptions opts) const { auto explain = opts.verbosity; if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { + // TODO: SERVER-76208 support query shapification for IDL types with custom serializers. MONGO_UNIMPLEMENTED_TASSERT(7484324); } diff --git a/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp b/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp index 6e16e5a9d0f..965173f29d5 100644 --- a/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp +++ b/src/mongo/db/pipeline/document_source_set_variable_from_subpipeline.cpp @@ -55,6 +55,8 @@ REGISTER_INTERNAL_DOCUMENT_SOURCE(setVariableFromSubPipeline, Value DocumentSourceSetVariableFromSubPipeline::serialize(SerializationOptions opts) const { if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { + // TODO: SERVER-76208 support query shapification for IDL types like pipeline with custom + // serializers. MONGO_UNIMPLEMENTED_TASSERT(7484314); } diff --git a/src/mongo/db/pipeline/exchange_spec.idl b/src/mongo/db/pipeline/exchange_spec.idl index fd411056767..9bf0a5d9e84 100644 --- a/src/mongo/db/pipeline/exchange_spec.idl +++ b/src/mongo/db/pipeline/exchange_spec.idl @@ -46,25 +46,30 @@ enums: structs: ExchangeSpec: description: "exchange aggregation request specification" + query_shape_component: true fields: policy: type: ExchangePolicy description: A string indicating a policy of how documents are distributed to consumers. stability: stable + query_shape_literal: false consumers: type: int description: Number of consumers. stability: stable + query_shape_literal: true orderPreserving: type: bool default: false description: A flag indicating documents are merged while preserving the order. stability: stable + query_shape_literal: false bufferSize: type: int default: 16777216 description: The size of exchange buffers. stability: stable + query_shape_literal: true key: type: object default: "BSONObj()" @@ -74,14 +79,17 @@ structs: field listed here, or if any prefix of any path is multikey (i.e. an array is encountered while traversing a path listed here), then it is by definition sent to consumer 0. + query_shape_literal: true boundaries: type: array<object> optional: true description: Range/hash split points. stability: stable + query_shape_literal: true consumerIds: type: array<int> optional: true description: Mapping from a range index to a consumer id. stability: stable + query_shape_literal: true diff --git a/src/mongo/db/pipeline/storage_stats_spec.idl b/src/mongo/db/pipeline/storage_stats_spec.idl index a241dfb2b84..f74818fd729 100644 --- a/src/mongo/db/pipeline/storage_stats_spec.idl +++ b/src/mongo/db/pipeline/storage_stats_spec.idl @@ -36,18 +36,23 @@ structs: StorageStatsSpec: description: Represents the 'storageStats' argument to the $collStats stage. strict: false + query_shape_component: true fields: scale: description: A number to use as a scaling factor applied to reported metrics. type: safeInt optional: true validator: { gte: 1 } + query_shape_literal: true verbose: type: optionalBool default: false + query_shape_literal: false waitForLock: type: optionalBool default: true + query_shape_literal: false numericOnly: type: optionalBool default: false + query_shape_literal: false diff --git a/src/mongo/db/query/query_shape_test.idl b/src/mongo/db/query/query_shape_test.idl index 4617692aa0f..caea731e651 100644 --- a/src/mongo/db/query/query_shape_test.idl +++ b/src/mongo/db/query/query_shape_test.idl @@ -64,10 +64,10 @@ structs: query_shape_literal: true type: array<int> fieldpath: - query_shape_fieldpath: true + query_shape_anonymize: true type: string fieldpathList: - query_shape_fieldpath: true + query_shape_anonymize: true type: array<string> ParentStruct: diff --git a/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp b/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp index b7db42cf4cb..271e0f9dea1 100644 --- a/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp +++ b/src/mongo/db/s/document_source_analyze_shard_key_read_write_distribution.cpp @@ -315,6 +315,8 @@ DocumentSourceAnalyzeShardKeyReadWriteDistribution::createFromBson( Value DocumentSourceAnalyzeShardKeyReadWriteDistribution::serialize( SerializationOptions opts) const { if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { + // TODO: SERVER-76208 support query shapification for IDL types like KeyPattern with custom + // serializers. MONGO_UNIMPLEMENTED_TASSERT(7484305); } diff --git a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp index dd4a900f812..42056f44f65 100644 --- a/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp +++ b/src/mongo/db/s/resharding/document_source_resharding_ownership_match.cpp @@ -94,6 +94,8 @@ StageConstraints DocumentSourceReshardingOwnershipMatch::constraints( Value DocumentSourceReshardingOwnershipMatch::serialize(SerializationOptions opts) const { if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { + // TODO: SERVER-76208 support query shapification for IDL types like KeyPattern with custom + // serializers. MONGO_UNIMPLEMENTED_TASSERT(7484302); } diff --git a/src/mongo/s/query/document_source_merge_cursors.cpp b/src/mongo/s/query/document_source_merge_cursors.cpp index 9a35057412a..3ebff23110b 100644 --- a/src/mongo/s/query/document_source_merge_cursors.cpp +++ b/src/mongo/s/query/document_source_merge_cursors.cpp @@ -118,6 +118,8 @@ Value DocumentSourceMergeCursors::serialize(SerializationOptions opts) const { invariant(!_blockingResultsMerger); invariant(_armParams); if (opts.redactIdentifiers || opts.replacementForLiteralArgs) { + // TODO: SERVER-76208 support query shapification for IDL types like namespacestring with + // custom serializers. MONGO_UNIMPLEMENTED_TASSERT(7484301); } |