diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2017-04-14 16:06:18 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2017-04-20 13:22:12 -0400 |
commit | 0293c14cbdc5646d9f09f4fe5b2a27e6d540dce0 (patch) | |
tree | 427f823c34f54fcd8d7fa28969ce7f40c740a354 | |
parent | c08590a6ac9dc54c9d910822d47ea17140b56f89 (diff) | |
download | mongo-0293c14cbdc5646d9f09f4fe5b2a27e6d540dce0.tar.gz |
SERVER-28621 Parse BSON update expression into an UpdateNode tree
69 files changed, 1077 insertions, 187 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 698fc103a51..be946688dd3 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -33,6 +33,7 @@ env.SConscript( 'sorter', 'stats', 'storage', + 'update', 'views', ], exports=[ @@ -873,7 +874,6 @@ env.Library( "matcher/expressions_mongod_only", "op_observer_d", "ops/write_ops", - "ops/update_driver", "ops/write_ops_parsers", "pipeline/aggregation", "pipeline/serveronly", @@ -913,6 +913,7 @@ env.Library( "storage/storage_options", "storage/wiredtiger/storage_wiredtiger" if wiredtiger else [], "ttl_d", + "update/update_driver", "update_index_data", "views/views_mongod", ], diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index e8fb1d4b0b0..836d7278f83 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -46,9 +46,9 @@ env.Library('authcore', ['action_set.cpp', '$BUILD_DIR/mongo/crypto/scramauth', '$BUILD_DIR/mongo/db/catalog/document_validation', '$BUILD_DIR/mongo/db/common', - '$BUILD_DIR/mongo/db/ops/update_driver', '$BUILD_DIR/mongo/db/namespace_string', '$BUILD_DIR/mongo/db/service_context', + '$BUILD_DIR/mongo/db/update/update_driver', '$BUILD_DIR/mongo/util/md5', '$BUILD_DIR/mongo/util/net/network']) @@ -173,8 +173,8 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/matcher/expressions', - '$BUILD_DIR/mongo/db/ops/update_driver', '$BUILD_DIR/mongo/db/service_context', + '$BUILD_DIR/mongo/db/update/update_driver', 'authcore' ] ) diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp index 7b8d72ad1f7..f4fef4fde08 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -41,7 +41,7 @@ #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context_noop.h" -#include "mongo/db/ops/update_driver.h" +#include "mongo/db/update/update_driver.h" #include "mongo/platform/unordered_set.h" #include "mongo/stdx/memory.h" #include "mongo/util/map_util.h" diff --git a/src/mongo/db/auth/role_graph_update.cpp b/src/mongo/db/auth/role_graph_update.cpp index 3432890406c..d1b45e3b98d 100644 --- a/src/mongo/db/auth/role_graph_update.cpp +++ b/src/mongo/db/auth/role_graph_update.cpp @@ -35,7 +35,7 @@ #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/role_graph.h" #include "mongo/db/auth/user_management_commands_parser.h" -#include "mongo/db/ops/update_driver.h" +#include "mongo/db/update/update_driver.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index baacbe3e0c3..c9b6ad39f19 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -52,7 +52,6 @@ #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/repl/replication_coordinator_global.h" @@ -63,6 +62,7 @@ #include "mongo/db/storage/record_fetcher.h" #include "mongo/db/storage/record_store.h" #include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h" +#include "mongo/db/update/update_driver.h" #include "mongo/db/auth/user_document_parser.h" // XXX-ANDY #include "mongo/rpc/object_check.h" diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index 841667fc2e0..646f5ce934d 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -55,7 +55,6 @@ #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/repl/replication_coordinator_global.h" @@ -66,6 +65,7 @@ #include "mongo/db/storage/record_fetcher.h" #include "mongo/db/storage/record_store.h" #include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h" +#include "mongo/db/update/update_driver.h" #include "mongo/db/auth/user_document_parser.h" // XXX-ANDY #include "mongo/rpc/object_check.h" diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript index ba660d93d0f..af06b19c3bf 100644 --- a/src/mongo/db/exec/SConscript +++ b/src/mongo/db/exec/SConscript @@ -93,9 +93,9 @@ env.Library( "$BUILD_DIR/mongo/db/fts/base", "$BUILD_DIR/mongo/db/index/index_descriptor", "$BUILD_DIR/mongo/db/index/key_generator", - "$BUILD_DIR/mongo/db/ops/update_driver", "$BUILD_DIR/mongo/db/pipeline/pipeline", "$BUILD_DIR/mongo/db/repl/repl_coordinator_global", + "$BUILD_DIR/mongo/db/update/update_driver", "$BUILD_DIR/mongo/scripting/scripting", "$BUILD_DIR/mongo/db/storage/storage_options", "$BUILD_DIR/mongo/s/common", diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp index 2846acbc245..edf0386d042 100644 --- a/src/mongo/db/exec/projection_exec.cpp +++ b/src/mongo/db/exec/projection_exec.cpp @@ -32,9 +32,9 @@ #include "mongo/db/exec/working_set_computed_data.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_parser.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/query_request.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/exec/update.h b/src/mongo/db/exec/update.h index e88a26e445b..fa866f87606 100644 --- a/src/mongo/db/exec/update.h +++ b/src/mongo/db/exec/update.h @@ -32,9 +32,9 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/exec/plan_stage.h" #include "mongo/db/jsobj.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/ops/update_result.h" +#include "mongo/db/update/update_driver.h" namespace mongo { diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript index 43a97cc2c47..de8e3b27176 100644 --- a/src/mongo/db/ops/SConscript +++ b/src/mongo/db/ops/SConscript @@ -5,54 +5,6 @@ Import("env") env = env.Clone() env.Library( - target='update_common', - source=[ - 'field_checker.cpp', - 'log_builder.cpp', - 'path_support.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/bson/mutable/mutable_bson', - '$BUILD_DIR/mongo/db/common', - '$BUILD_DIR/mongo/db/matcher/expressions', - ], -) - -env.CppUnitTest( - target='field_checker_test', - source=[ - 'field_checker_test.cpp', - ], - LIBDEPS=[ - 'update_common', - ], -) - -env.CppUnitTest( - target='log_builder_test', - source=[ - 'log_builder_test.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - 'update_common', - ], -) - -env.CppUnitTest( - target='path_support_test', - source=[ - 'path_support_test.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - '$BUILD_DIR/mongo/db/matcher/expressions', - 'update_common', - ], -) - -env.Library( target='update', source=[ 'modifier_add_to_set.cpp', @@ -76,7 +28,7 @@ env.Library( '$BUILD_DIR/mongo/db/logical_time', '$BUILD_DIR/mongo/db/bson/dotted_path_support', '$BUILD_DIR/mongo/db/matcher/expressions', - 'update_common', + '$BUILD_DIR/mongo/db/update/update_common', ], ) @@ -212,40 +164,6 @@ env.CppUnitTest( ) env.Library( - target='update_driver', - source=[ - 'modifier_table.cpp', - 'update_driver.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/db/common', - '$BUILD_DIR/mongo/db/query/query_planner', - '$BUILD_DIR/mongo/db/update_index_data', - 'update', - ], -) - -env.CppUnitTest( - target='modifier_table_test', - source='modifier_table_test.cpp', - LIBDEPS=[ - 'update_driver', - ], -) - -env.CppUnitTest( - target='update_driver_test', - source='update_driver_test.cpp', - LIBDEPS=[ - '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', - '$BUILD_DIR/mongo/db/query/query_planner', - '$BUILD_DIR/mongo/db/query/query_test_service_context', - 'update_driver', - ], -) - -env.Library( target='write_ops_parsers', source=[ 'write_ops_parsers.cpp', @@ -266,25 +184,6 @@ env.CppUnitTest( ) env.Library( - target='array_filter', - source=[ - 'array_filter.cpp', - ], - LIBDEPS=[ - "$BUILD_DIR/mongo/db/matcher/expressions", - ], -) - -env.CppUnitTest( - target='array_filter_test', - source='array_filter_test.cpp', - LIBDEPS=[ - 'array_filter', - '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', - ], -) - -env.Library( target="write_ops", source=[ "delete.cpp", @@ -297,14 +196,14 @@ env.Library( "write_ops_exec.cpp", ], LIBDEPS=[ - 'array_filter', - 'update_driver', '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/concurrency/lock_manager', '$BUILD_DIR/mongo/db/matcher/expressions_mongod_only', '$BUILD_DIR/mongo/db/query/query', '$BUILD_DIR/mongo/db/repl/repl_coordinator_impl', '$BUILD_DIR/mongo/db/service_context', + '$BUILD_DIR/mongo/db/update/array_filter', + '$BUILD_DIR/mongo/db/update/update_driver', '$BUILD_DIR/mongo/db/introspect', '$BUILD_DIR/mongo/db/curop_metrics', #'$BUILD_DIR/mongo/db/catalog/catalog', # CYCLE diff --git a/src/mongo/db/ops/modifier_add_to_set.cpp b/src/mongo/db/ops/modifier_add_to_set.cpp index a565800d749..fbe87014526 100644 --- a/src/mongo/db/ops/modifier_add_to_set.cpp +++ b/src/mongo/db/ops/modifier_add_to_set.cpp @@ -30,10 +30,10 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/collation/collator_interface.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_add_to_set_test.cpp b/src/mongo/db/ops/modifier_add_to_set_test.cpp index 235a65239e6..dce3d2a3772 100644 --- a/src/mongo/db/ops/modifier_add_to_set_test.cpp +++ b/src/mongo/db/ops/modifier_add_to_set_test.cpp @@ -36,8 +36,8 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_bit.cpp b/src/mongo/db/ops/modifier_bit.cpp index fb7ae3f45eb..2e59b8a2f4e 100644 --- a/src/mongo/db/ops/modifier_bit.cpp +++ b/src/mongo/db/ops/modifier_bit.cpp @@ -31,9 +31,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_bit_test.cpp b/src/mongo/db/ops/modifier_bit_test.cpp index dbc4d7ba0b2..3c8fed4330e 100644 --- a/src/mongo/db/ops/modifier_bit_test.cpp +++ b/src/mongo/db/ops/modifier_bit_test.cpp @@ -36,7 +36,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/unittest.h" diff --git a/src/mongo/db/ops/modifier_compare.cpp b/src/mongo/db/ops/modifier_compare.cpp index 4e366f90ee2..fdf73982adf 100644 --- a/src/mongo/db/ops/modifier_compare.cpp +++ b/src/mongo/db/ops/modifier_compare.cpp @@ -30,10 +30,10 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/collation/collator_interface.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_compare_test.cpp b/src/mongo/db/ops/modifier_compare_test.cpp index 9bc036b776b..c454e741368 100644 --- a/src/mongo/db/ops/modifier_compare_test.cpp +++ b/src/mongo/db/ops/modifier_compare_test.cpp @@ -35,8 +35,8 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_current_date.cpp b/src/mongo/db/ops/modifier_current_date.cpp index 78dc3c57d4f..a7d301bbe86 100644 --- a/src/mongo/db/ops/modifier_current_date.cpp +++ b/src/mongo/db/ops/modifier_current_date.cpp @@ -34,10 +34,10 @@ #include "mongo/bson/mutable/document.h" #include "mongo/db/logical_clock.h" #include "mongo/db/logical_time.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/service_context.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_current_date_test.cpp b/src/mongo/db/ops/modifier_current_date_test.cpp index a9f0865c8be..0c6241eba90 100644 --- a/src/mongo/db/ops/modifier_current_date_test.cpp +++ b/src/mongo/db/ops/modifier_current_date_test.cpp @@ -36,7 +36,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/logical_clock_test_fixture.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_inc.cpp b/src/mongo/db/ops/modifier_inc.cpp index 314ac6a5024..1692d71260f 100644 --- a/src/mongo/db/ops/modifier_inc.cpp +++ b/src/mongo/db/ops/modifier_inc.cpp @@ -31,9 +31,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_inc_test.cpp b/src/mongo/db/ops/modifier_inc_test.cpp index 02fbbd4474a..ec12b8deb66 100644 --- a/src/mongo/db/ops/modifier_inc_test.cpp +++ b/src/mongo/db/ops/modifier_inc_test.cpp @@ -38,7 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/platform/decimal128.h" #include "mongo/unittest/unittest.h" diff --git a/src/mongo/db/ops/modifier_object_replace.cpp b/src/mongo/db/ops/modifier_object_replace.cpp index e74617ea7ef..e77759e6997 100644 --- a/src/mongo/db/ops/modifier_object_replace.cpp +++ b/src/mongo/db/ops/modifier_object_replace.cpp @@ -33,8 +33,8 @@ #include "mongo/bson/mutable/document.h" #include "mongo/db/logical_clock.h" #include "mongo/db/logical_time.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/service_context.h" +#include "mongo/db/update/log_builder.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_object_replace_test.cpp b/src/mongo/db/ops/modifier_object_replace_test.cpp index c661246e7f5..5b7165f600d 100644 --- a/src/mongo/db/ops/modifier_object_replace_test.cpp +++ b/src/mongo/db/ops/modifier_object_replace_test.cpp @@ -40,7 +40,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/logical_clock_test_fixture.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_pop.cpp b/src/mongo/db/ops/modifier_pop.cpp index 07682c976bf..faac70222d5 100644 --- a/src/mongo/db/ops/modifier_pop.cpp +++ b/src/mongo/db/ops/modifier_pop.cpp @@ -31,9 +31,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_pop_test.cpp b/src/mongo/db/ops/modifier_pop_test.cpp index 8e288c73aa4..75cb61fac71 100644 --- a/src/mongo/db/ops/modifier_pop_test.cpp +++ b/src/mongo/db/ops/modifier_pop_test.cpp @@ -38,7 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_pull.cpp b/src/mongo/db/ops/modifier_pull.cpp index 9a7b8608555..75bfaa4aa30 100644 --- a/src/mongo/db/ops/modifier_pull.cpp +++ b/src/mongo/db/ops/modifier_pull.cpp @@ -32,10 +32,10 @@ #include "mongo/bson/mutable/algorithm.h" #include "mongo/db/matcher/expression_parser.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/collation/collator_interface.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_pull_all.cpp b/src/mongo/db/ops/modifier_pull_all.cpp index 2d57bea1cb5..26a3d6d24ff 100644 --- a/src/mongo/db/ops/modifier_pull_all.cpp +++ b/src/mongo/db/ops/modifier_pull_all.cpp @@ -31,10 +31,10 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/collation/collator_interface.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_pull_all_test.cpp b/src/mongo/db/ops/modifier_pull_all_test.cpp index 02fd8b7fd7f..f24c770aa48 100644 --- a/src/mongo/db/ops/modifier_pull_all_test.cpp +++ b/src/mongo/db/ops/modifier_pull_all_test.cpp @@ -38,8 +38,8 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_pull_test.cpp b/src/mongo/db/ops/modifier_pull_test.cpp index 4e23c9beab4..6d465442dfe 100644 --- a/src/mongo/db/ops/modifier_pull_test.cpp +++ b/src/mongo/db/ops/modifier_pull_test.cpp @@ -36,8 +36,8 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_push.cpp b/src/mongo/db/ops/modifier_push.cpp index d2d816776fa..6be330cc98f 100644 --- a/src/mongo/db/ops/modifier_push.cpp +++ b/src/mongo/db/ops/modifier_push.cpp @@ -36,9 +36,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" diff --git a/src/mongo/db/ops/modifier_push_test.cpp b/src/mongo/db/ops/modifier_push_test.cpp index c4a05aafa7f..008bb140933 100644 --- a/src/mongo/db/ops/modifier_push_test.cpp +++ b/src/mongo/db/ops/modifier_push_test.cpp @@ -42,8 +42,8 @@ #include "mongo/db/bson/dotted_path_support.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/query/collation/collator_interface_mock.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" #include "mongo/util/mongoutils/str.h" diff --git a/src/mongo/db/ops/modifier_rename.cpp b/src/mongo/db/ops/modifier_rename.cpp index c2935fb1906..20ca8d67e49 100644 --- a/src/mongo/db/ops/modifier_rename.cpp +++ b/src/mongo/db/ops/modifier_rename.cpp @@ -31,9 +31,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/algorithm.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_rename_test.cpp b/src/mongo/db/ops/modifier_rename_test.cpp index aab70c00376..fc1c4ee108d 100644 --- a/src/mongo/db/ops/modifier_rename_test.cpp +++ b/src/mongo/db/ops/modifier_rename_test.cpp @@ -37,7 +37,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_set.cpp b/src/mongo/db/ops/modifier_set.cpp index 59f59c555ce..77575fc76a9 100644 --- a/src/mongo/db/ops/modifier_set.cpp +++ b/src/mongo/db/ops/modifier_set.cpp @@ -30,9 +30,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_set_test.cpp b/src/mongo/db/ops/modifier_set_test.cpp index 1579b096722..354aae01929 100644 --- a/src/mongo/db/ops/modifier_set_test.cpp +++ b/src/mongo/db/ops/modifier_set_test.cpp @@ -38,7 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/modifier_unset.cpp b/src/mongo/db/ops/modifier_unset.cpp index 453b2d60d1c..a70db3c8fd4 100644 --- a/src/mongo/db/ops/modifier_unset.cpp +++ b/src/mongo/db/ops/modifier_unset.cpp @@ -30,9 +30,9 @@ #include "mongo/base/error_codes.h" #include "mongo/bson/mutable/document.h" -#include "mongo/db/ops/field_checker.h" -#include "mongo/db/ops/log_builder.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/modifier_unset_test.cpp b/src/mongo/db/ops/modifier_unset_test.cpp index af6ad9581a7..dfffe5be383 100644 --- a/src/mongo/db/ops/modifier_unset_test.cpp +++ b/src/mongo/db/ops/modifier_unset_test.cpp @@ -38,7 +38,7 @@ #include "mongo/bson/mutable/mutable_bson_test_utils.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/unittest/unittest.h" namespace { diff --git a/src/mongo/db/ops/parsed_update.h b/src/mongo/db/ops/parsed_update.h index 8c448bd8e58..1c41b07f257 100644 --- a/src/mongo/db/ops/parsed_update.h +++ b/src/mongo/db/ops/parsed_update.h @@ -30,10 +30,10 @@ #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" -#include "mongo/db/ops/array_filter.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/plan_executor.h" +#include "mongo/db/update/array_filter.h" +#include "mongo/db/update/update_driver.h" namespace mongo { diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index eaeb014009b..0e5a11e2a0f 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -44,13 +44,13 @@ #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/exec/update.h" #include "mongo/db/op_observer.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_lifecycle.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_summary_stats.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/replication_coordinator_global.h" +#include "mongo/db/update/update_driver.h" #include "mongo/db/update_index_data.h" #include "mongo/util/log.h" #include "mongo/util/scopeguard.h" diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index 6a13341c111..daf079bb56f 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -29,7 +29,6 @@ #include "mongo/db/ops/delete_request.h" #include "mongo/db/ops/parsed_delete.h" #include "mongo/db/ops/parsed_update.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/parsed_distinct.h" @@ -37,6 +36,7 @@ #include "mongo/db/query/query_planner_params.h" #include "mongo/db/query/query_settings.h" #include "mongo/db/query/query_solution.h" +#include "mongo/db/update/update_driver.h" namespace mongo { diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript new file mode 100644 index 00000000000..2bf1d3b756b --- /dev/null +++ b/src/mongo/db/update/SConscript @@ -0,0 +1,135 @@ +# -*- mode: python -*- + +Import("env") + +env = env.Clone() + +env.Library( + target='update_common', + source=[ + 'field_checker.cpp', + 'log_builder.cpp', + 'path_support.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/bson/mutable/mutable_bson', + '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/matcher/expressions', + ], +) + +env.CppUnitTest( + target='field_checker_test', + source=[ + 'field_checker_test.cpp', + ], + LIBDEPS=[ + 'update_common', + ], +) + +env.CppUnitTest( + target='log_builder_test', + source=[ + 'log_builder_test.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', + 'update_common', + ], +) + +env.CppUnitTest( + target='path_support_test', + source=[ + 'path_support_test.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', + '$BUILD_DIR/mongo/db/matcher/expressions', + 'update_common', + ], +) + +env.Library( + target='update', + source=[ + 'modifier_table.cpp', + 'set_node.cpp', + 'update_object_node.cpp' + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/ops/update', + 'update_common', + ], +) + +env.CppUnitTest( + target='modifier_table_test', + source='modifier_table_test.cpp', + LIBDEPS=[ + 'update', + ], +) + +env.CppUnitTest( + target='set_node_test', + source='set_node_test.cpp', + LIBDEPS=[ + 'update', + ], +) + +env.CppUnitTest( + target='update_object_node_test', + source='update_object_node_test.cpp', + LIBDEPS=[ + 'update', + ], +) + +env.Library( + target='update_driver', + source=[ + 'update_driver.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/ops/update', + '$BUILD_DIR/mongo/db/query/query_planner', + '$BUILD_DIR/mongo/db/update_index_data', + 'update', + ], +) + +env.CppUnitTest( + target='update_driver_test', + source='update_driver_test.cpp', + LIBDEPS=[ + '$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils', + '$BUILD_DIR/mongo/db/query/query_planner', + '$BUILD_DIR/mongo/db/query/query_test_service_context', + 'update_driver', + ], +) + +env.Library( + target='array_filter', + source=[ + 'array_filter.cpp', + ], + LIBDEPS=[ + "$BUILD_DIR/mongo/db/matcher/expressions", + ], +) + +env.CppUnitTest( + target='array_filter_test', + source='array_filter_test.cpp', + LIBDEPS=[ + 'array_filter', + '$BUILD_DIR/mongo/db/query/collation/collator_interface_mock', + ], +) diff --git a/src/mongo/db/ops/array_filter.cpp b/src/mongo/db/update/array_filter.cpp index 55c42c7e0a1..4ebaf734498 100644 --- a/src/mongo/db/ops/array_filter.cpp +++ b/src/mongo/db/update/array_filter.cpp @@ -28,7 +28,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/ops/array_filter.h" +#include "mongo/db/update/array_filter.h" #include "mongo/db/matcher/expression_parser.h" diff --git a/src/mongo/db/ops/array_filter.h b/src/mongo/db/update/array_filter.h index fc9685ce520..fc9685ce520 100644 --- a/src/mongo/db/ops/array_filter.h +++ b/src/mongo/db/update/array_filter.h diff --git a/src/mongo/db/ops/array_filter_test.cpp b/src/mongo/db/update/array_filter_test.cpp index d79ffc2e683..a0c24ba2875 100644 --- a/src/mongo/db/ops/array_filter_test.cpp +++ b/src/mongo/db/update/array_filter_test.cpp @@ -28,7 +28,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/ops/array_filter.h" +#include "mongo/db/update/array_filter.h" #include "mongo/db/json.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" diff --git a/src/mongo/db/ops/field_checker.cpp b/src/mongo/db/update/field_checker.cpp index 4e8c8b82de6..9821ba168b2 100644 --- a/src/mongo/db/ops/field_checker.cpp +++ b/src/mongo/db/update/field_checker.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/field_checker.h" +#include "mongo/db/update/field_checker.h" #include "mongo/base/error_codes.h" #include "mongo/db/field_ref.h" diff --git a/src/mongo/db/ops/field_checker.h b/src/mongo/db/update/field_checker.h index 772034d4773..772034d4773 100644 --- a/src/mongo/db/ops/field_checker.h +++ b/src/mongo/db/update/field_checker.h diff --git a/src/mongo/db/ops/field_checker_test.cpp b/src/mongo/db/update/field_checker_test.cpp index 5ee608688e9..ff35815a254 100644 --- a/src/mongo/db/ops/field_checker_test.cpp +++ b/src/mongo/db/update/field_checker_test.cpp @@ -26,7 +26,7 @@ * then also delete it in the license file. */ -#include "mongo/db/ops/field_checker.h" +#include "mongo/db/update/field_checker.h" #include "mongo/base/error_codes.h" #include "mongo/base/status.h" diff --git a/src/mongo/db/ops/log_builder.cpp b/src/mongo/db/update/log_builder.cpp index 355ccb092e8..deddbab3840 100644 --- a/src/mongo/db/ops/log_builder.cpp +++ b/src/mongo/db/update/log_builder.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/util/mongoutils/str.h" namespace mongo { diff --git a/src/mongo/db/ops/log_builder.h b/src/mongo/db/update/log_builder.h index 0d667f94151..0d667f94151 100644 --- a/src/mongo/db/ops/log_builder.h +++ b/src/mongo/db/update/log_builder.h diff --git a/src/mongo/db/ops/log_builder_test.cpp b/src/mongo/db/update/log_builder_test.cpp index a957194e56f..27757de756f 100644 --- a/src/mongo/db/ops/log_builder_test.cpp +++ b/src/mongo/db/update/log_builder_test.cpp @@ -26,7 +26,7 @@ * then also delete it in the license file. */ -#include "mongo/db/ops/log_builder.h" +#include "mongo/db/update/log_builder.h" #include "mongo/base/status.h" #include "mongo/bson/mutable/mutable_bson_test_utils.h" diff --git a/src/mongo/db/ops/modifier_table.cpp b/src/mongo/db/update/modifier_table.cpp index cd4f0670184..008973980d8 100644 --- a/src/mongo/db/ops/modifier_table.cpp +++ b/src/mongo/db/update/modifier_table.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/modifier_table.h" +#include "mongo/db/update/modifier_table.h" #include <string> #include <utility> @@ -46,7 +46,9 @@ #include "mongo/db/ops/modifier_rename.h" #include "mongo/db/ops/modifier_set.h" #include "mongo/db/ops/modifier_unset.h" +#include "mongo/db/update/set_node.h" #include "mongo/platform/unordered_map.h" +#include "mongo/stdx/memory.h" namespace mongo { @@ -175,5 +177,14 @@ ModifierInterface* makeUpdateMod(ModifierType modType) { } } +std::unique_ptr<UpdateLeafNode> makeUpdateLeafNode(ModifierType modType) { + switch (modType) { + case MOD_SET: + return stdx::make_unique<SetNode>(); + default: + return nullptr; + } +} + } // namespace modifiertable } // namespace mongo diff --git a/src/mongo/db/ops/modifier_table.h b/src/mongo/db/update/modifier_table.h index acefc3290dc..ad5262fb1b0 100644 --- a/src/mongo/db/ops/modifier_table.h +++ b/src/mongo/db/update/modifier_table.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/db/ops/modifier_interface.h" +#include "mongo/db/update/update_leaf_node.h" namespace mongo { namespace modifiertable { @@ -66,5 +67,10 @@ ModifierType getType(StringData typeStr); */ ModifierInterface* makeUpdateMod(ModifierType modType); +/** + * Instantiate an UpdateLeafNode that corresponds to 'modType' or nullptr if 'modType' is not valid. + */ +std::unique_ptr<UpdateLeafNode> makeUpdateLeafNode(ModifierType modType); + } // namespace modifiertable } // namespace mongo diff --git a/src/mongo/db/ops/modifier_table_test.cpp b/src/mongo/db/update/modifier_table_test.cpp index c5225142668..ca3f82cc1c5 100644 --- a/src/mongo/db/ops/modifier_table_test.cpp +++ b/src/mongo/db/update/modifier_table_test.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/modifier_table.h" +#include "mongo/db/update/modifier_table.h" #include <memory> diff --git a/src/mongo/db/ops/path_support.cpp b/src/mongo/db/update/path_support.cpp index a95b700acd0..5e336bb8202 100644 --- a/src/mongo/db/ops/path_support.cpp +++ b/src/mongo/db/update/path_support.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/path_support.h" #include "mongo/base/string_data.h" #include "mongo/bson/mutable/algorithm.h" diff --git a/src/mongo/db/ops/path_support.h b/src/mongo/db/update/path_support.h index 6fbd95ec0a9..6fbd95ec0a9 100644 --- a/src/mongo/db/ops/path_support.h +++ b/src/mongo/db/update/path_support.h diff --git a/src/mongo/db/ops/path_support_test.cpp b/src/mongo/db/update/path_support_test.cpp index 527384ab7bb..5091a2b8cba 100644 --- a/src/mongo/db/ops/path_support_test.cpp +++ b/src/mongo/db/update/path_support_test.cpp @@ -26,7 +26,7 @@ * then also delete it in the license file. */ -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/path_support.h" #include <cstdint> #include <memory> diff --git a/src/mongo/db/update/set_node.cpp b/src/mongo/db/update/set_node.cpp new file mode 100644 index 00000000000..26c6be59ee3 --- /dev/null +++ b/src/mongo/db/update/set_node.cpp @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/update/set_node.h" + +namespace mongo { + +Status SetNode::init(BSONElement modExpr, const CollatorInterface* collator) { + invariant(modExpr.ok()); + + _val = modExpr; + + return Status::OK(); +} + +} // namespace mongo diff --git a/src/mongo/db/update/set_node.h b/src/mongo/db/update/set_node.h new file mode 100644 index 00000000000..8ad64010a50 --- /dev/null +++ b/src/mongo/db/update/set_node.h @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/db/update/update_leaf_node.h" + +namespace mongo { + +/** + * Represents the application of a $set to the value at the end of a path. + */ +class SetNode : public UpdateLeafNode { +public: + Status init(BSONElement modExpr, const CollatorInterface* collator) final; + + void setCollator(const CollatorInterface* collator) final {} + +private: + BSONElement _val; +}; + +} // namespace mongo diff --git a/src/mongo/db/update/set_node_test.cpp b/src/mongo/db/update/set_node_test.cpp new file mode 100644 index 00000000000..c600af34158 --- /dev/null +++ b/src/mongo/db/update/set_node_test.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/update/set_node.h" + +#include "mongo/db/json.h" +#include "mongo/unittest/death_test.h" +#include "mongo/unittest/unittest.h" + +namespace { + +using namespace mongo; + +DEATH_TEST(SetNodeTest, InitFailsForEmptyElement, "Invariant failure modExpr.ok()") { + auto update = fromjson("{$set: {}}"); + const CollatorInterface* collator = nullptr; + SetNode node; + node.init(update["$set"].embeddedObject().firstElement(), collator); +} + +TEST(SetNodeTest, InitSucceedsForNonemptyElement) { + auto update = fromjson("{$set: {a: 5}}"); + const CollatorInterface* collator = nullptr; + SetNode node; + ASSERT_OK(node.init(update["$set"]["a"], collator)); +} + +} // namespace diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index f94f520f032..d13118e4ed4 100644 --- a/src/mongo/db/ops/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/update_driver.h" +#include "mongo/db/update/update_driver.h" #include "mongo/base/error_codes.h" @@ -36,10 +36,10 @@ #include "mongo/db/field_ref.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/extensions_callback_noop.h" -#include "mongo/db/ops/log_builder.h" #include "mongo/db/ops/modifier_object_replace.h" -#include "mongo/db/ops/modifier_table.h" -#include "mongo/db/ops/path_support.h" +#include "mongo/db/update/log_builder.h" +#include "mongo/db/update/modifier_table.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/embedded_builder.h" #include "mongo/util/mongoutils/str.h" diff --git a/src/mongo/db/ops/update_driver.h b/src/mongo/db/update/update_driver.h index 73f231f9764..6152e22cefb 100644 --- a/src/mongo/db/ops/update_driver.h +++ b/src/mongo/db/update/update_driver.h @@ -37,8 +37,8 @@ #include "mongo/db/field_ref_set.h" #include "mongo/db/jsobj.h" #include "mongo/db/ops/modifier_interface.h" -#include "mongo/db/ops/modifier_table.h" #include "mongo/db/query/canonical_query.h" +#include "mongo/db/update/modifier_table.h" #include "mongo/db/update_index_data.h" namespace mongo { diff --git a/src/mongo/db/ops/update_driver_test.cpp b/src/mongo/db/update/update_driver_test.cpp index c7ef14b3e9f..b2e98556d16 100644 --- a/src/mongo/db/ops/update_driver_test.cpp +++ b/src/mongo/db/update/update_driver_test.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/ops/update_driver.h" +#include "mongo/db/update/update_driver.h" #include <map> diff --git a/src/mongo/db/update/update_leaf_node.h b/src/mongo/db/update/update_leaf_node.h new file mode 100644 index 00000000000..2b378036c7d --- /dev/null +++ b/src/mongo/db/update/update_leaf_node.h @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/bson/bsonelement.h" +#include "mongo/db/update/update_node.h" + +namespace mongo { + +/** + * A leaf node in the prefix tree of update modifier expressions, representing an update to the + * value at the end of a path. See comment in class definition of UpdateNode for more details. + */ +class UpdateLeafNode : public UpdateNode { +public: + UpdateLeafNode() : UpdateNode(Type::Leaf) {} + + /** + * Initializes the leaf node with the value in 'modExpr'. 'modExpr' is a single modifier + * expression in the update expression. For example, if the update expression is root = {$set: + * {'a.b': 5, c: 6}, $inc: {'a.c': 1}}, then a single modifier expression would be + * root["$set"]["a.b"]. Returns a non-OK status if the value in 'modExpr' is invalid for the + * type of leaf node. 'modExpr' must not be empty. + * + * Some leaf nodes require a collator during initialization. For example, $pull requires a + * collator to construct a MatchExpression that will be used for applying updates across + * multiple documents. + */ + virtual Status init(BSONElement modExpr, const CollatorInterface* collator) = 0; +}; + +} // namespace mongo diff --git a/src/mongo/db/update/update_node.h b/src/mongo/db/update/update_node.h new file mode 100644 index 00000000000..4336ab17cd5 --- /dev/null +++ b/src/mongo/db/update/update_node.h @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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 + +namespace mongo { + +class CollatorInterface; + +/** + * Update modifier expressions are stored as a prefix tree of UpdateNodes, where two modifiers that + * share a field path prefix share a path prefix in the tree. The prefix tree is used to enforce + * that no update modifier's field path is a prefix of (or equal to) another update modifier's field + * path. The root of the UpdateNode tree is always an UpdateObjectNode. The leaves are always + * UpdateLeafNodes. + * + * Example: {$set: {'a.b': 5, c: 6}, $inc: {'a.c': 1}} + * + * UpdateObjectNode + * a / \ c + * UpdateObjectNode SetNode: _val = 6 + * b / \ c + * SetNode: _val = 5 IncNode: _val = 1 + */ +class UpdateNode { +public: + enum class Type { Object, Leaf }; + + explicit UpdateNode(Type type) : type(type) {} + + /** + * Set the collation on the node and all descendants. This is a noop if no leaf nodes require a + * collator. If setCollator() is called, it is required that the current collator of all leaf + * nodes is the simple collator (nullptr). The collator must outlive the modifier interface. + * This is used to override the collation after obtaining a collection lock if the update did + * not specify a collation and the collection has a non-simple default collation. + */ + virtual void setCollator(const CollatorInterface* collator) = 0; + + const Type type; +}; + +} // namespace mongo diff --git a/src/mongo/db/update/update_object_node.cpp b/src/mongo/db/update/update_object_node.cpp new file mode 100644 index 00000000000..12794c5b0dc --- /dev/null +++ b/src/mongo/db/update/update_object_node.cpp @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/update/update_object_node.h" + +#include "mongo/db/update/field_checker.h" +#include "mongo/db/update/modifier_table.h" +#include "mongo/db/update/update_leaf_node.h" +#include "mongo/stdx/memory.h" + +namespace mongo { + +namespace { + +bool isPositionalElement(const std::string& field) { + return field.length() == 1 && field[0] == '$'; +} + +} // namespace + +// static +StatusWith<bool> UpdateObjectNode::parseAndMerge(UpdateObjectNode* root, + modifiertable::ModifierType type, + BSONElement modExpr, + const CollatorInterface* collator) { + // Check that the path is updatable. + FieldRef fieldRef(modExpr.fieldNameStringData()); + auto status = fieldchecker::isUpdatable(fieldRef); + if (!status.isOK()) { + return status; + } + + // Check that there is at most one positional ($) part of the path and it is not in the first + // position. + size_t positionalIndex; + size_t positionalCount; + bool positional = fieldchecker::isPositional(fieldRef, &positionalIndex, &positionalCount); + + if (positional && positionalCount > 1) { + return Status(ErrorCodes::BadValue, + str::stream() << "Too many positional (i.e. '$') elements found in path '" + << fieldRef.dottedField() + << "'"); + } + + if (positional && positionalIndex == 0) { + return Status( + ErrorCodes::BadValue, + str::stream() + << "Cannot have positional (i.e. '$') element in the first position in path '" + << fieldRef.dottedField() + << "'"); + } + + // Construct the leaf node. + // TODO SERVER-28777: This should never fail because all modifiers are implemented. + auto leaf = modifiertable::makeUpdateLeafNode(type); + if (!leaf) { + return Status(ErrorCodes::FailedToParse, + str::stream() << "Cannot construct modifier of type " << type); + } + + // Initialize the leaf node. + status = leaf->init(modExpr, collator); + if (!status.isOK()) { + return status; + } + + // Create UpdateObjectNodes along the path. + UpdateObjectNode* current = root; + for (size_t i = 0; i < fieldRef.numParts() - 1; ++i) { + auto field = fieldRef.getPart(i).toString(); + auto child = current->getChild(field); + if (child) { + if (child->type != UpdateNode::Type::Object) { + return Status(ErrorCodes::ConflictingUpdateOperators, + str::stream() << "Updating the path '" << fieldRef.dottedField() + << "' would create a conflict at '" + << fieldRef.dottedSubstring(0, i + 1) + << "'"); + } + } else { + auto ownedChild = stdx::make_unique<UpdateObjectNode>(); + child = ownedChild.get(); + current->setChild(std::move(field), std::move(ownedChild)); + } + current = static_cast<UpdateObjectNode*>(child); + } + + // Add the leaf node to the end of the path. + auto field = fieldRef.getPart(fieldRef.numParts() - 1).toString(); + if (current->getChild(field)) { + return Status(ErrorCodes::ConflictingUpdateOperators, + str::stream() << "Updating the path '" << fieldRef.dottedField() + << "' would create a conflict at '" + << fieldRef.dottedField() + << "'"); + } + current->setChild(std::move(field), std::move(leaf)); + + return positional; +} + +UpdateNode* UpdateObjectNode::getChild(const std::string& field) const { + if (isPositionalElement(field)) { + return _positionalChild.get(); + } + + auto child = _children.find(field); + if (child == _children.end()) { + return nullptr; + } + return child->second.get(); +} + +void UpdateObjectNode::setChild(std::string field, std::unique_ptr<UpdateNode> child) { + if (isPositionalElement(field)) { + invariant(!_positionalChild); + _positionalChild = std::move(child); + } else { + invariant(_children.find(field) == _children.end()); + _children[std::move(field)] = std::move(child); + } +} + +} // namespace mongo diff --git a/src/mongo/db/update/update_object_node.h b/src/mongo/db/update/update_object_node.h new file mode 100644 index 00000000000..55d305a1d30 --- /dev/null +++ b/src/mongo/db/update/update_object_node.h @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/bson/bsonelement.h" +#include "mongo/db/update/modifier_table.h" +#include "mongo/db/update/update_node.h" + +namespace mongo { + +/** + * An internal node in the prefix tree of update modifier expressions, representing updates to an + * object. See comment in class definition of UpdateNode for more details. + */ +class UpdateObjectNode : public UpdateNode { + +public: + /** + * Parses 'modExpr' as an update modifier expression and merges with it with 'root'. Returns a + * non-OK status if 'modExpr' is not a valid update modifier expression, or if merging would + * cause a conflict. Returns true if the path of 'modExpr' contains a positional $ element, e.g. + * 'a.$.b'. + */ + static StatusWith<bool> parseAndMerge(UpdateObjectNode* root, + modifiertable::ModifierType type, + BSONElement modExpr, + const CollatorInterface* collator); + + UpdateObjectNode() : UpdateNode(Type::Object) {} + + void setCollator(const CollatorInterface* collator) final { + for (auto&& child : _children) { + child.second->setCollator(collator); + } + _positionalChild->setCollator(collator); + } + + /** + * Returns the child with field name 'field' or nullptr if there is no such child. + */ + UpdateNode* getChild(const std::string& field) const; + + /** + * Adds a child with field name 'field'. The node must not already have a child with field + * name 'field'. + */ + void setChild(std::string field, std::unique_ptr<UpdateNode> child); + +private: + std::map<std::string, std::unique_ptr<UpdateNode>> _children; + std::unique_ptr<UpdateNode> _positionalChild; +}; + +} // namespace mongo diff --git a/src/mongo/db/update/update_object_node_test.cpp b/src/mongo/db/update/update_object_node_test.cpp new file mode 100644 index 00000000000..6143cd5f29c --- /dev/null +++ b/src/mongo/db/update/update_object_node_test.cpp @@ -0,0 +1,333 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/update/update_object_node.h" + +#include "mongo/db/json.h" +#include "mongo/unittest/unittest.h" + +namespace { + +using namespace mongo; + +TEST(UpdateObjectNodeTest, InvalidPathFailsToParse) { + auto update = fromjson("{$set: {'': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"][""], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::EmptyFieldName); + ASSERT_EQ(result.getStatus().reason(), "An empty update path is not valid."); +} + +TEST(UpdateObjectNodeTest, ValidPathParsesSuccessfully) { + auto update = fromjson("{$set: {'a.b': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator)); +} + +TEST(UpdateObjectNodeTest, MultiplePositionalElementsFailToParse) { + auto update = fromjson("{$set: {'a.$.b.$': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b.$"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); + ASSERT_EQ(result.getStatus().reason(), + "Too many positional (i.e. '$') elements found in path 'a.$.b.$'"); +} + +TEST(UpdateObjectNodeTest, ParsingSetsPositionalTrue) { + auto update = fromjson("{$set: {'a.$.b': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator); + ASSERT_OK(result); + ASSERT_TRUE(result.getValue()); +} + +TEST(UpdateObjectNodeTest, ParsingSetsPositionalFalse) { + auto update = fromjson("{$set: {'a.b': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator); + ASSERT_OK(result); + ASSERT_FALSE(result.getValue()); +} + +TEST(UpdateObjectNodeTest, PositionalElementFirstPositionFailsToParse) { + auto update = fromjson("{$set: {'$': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["$"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); + ASSERT_EQ(result.getStatus().reason(), + "Cannot have positional (i.e. '$') element in the first position in path '$'"); +} + +// TODO SERVER-28777: All modifier types should succeed. +TEST(UpdateObjectNodeTest, IncFailsToParse) { + auto update = fromjson("{$inc: {a: 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_INC, update["$inc"]["a"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse); + ASSERT_EQ(result.getStatus().reason(), "Cannot construct modifier of type 3"); +} + +TEST(UpdateObjectNodeTest, TwoModifiersOnSameFieldFailToParse) { + auto update = fromjson("{$set: {a: 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'"); +} + +TEST(UpdateObjectNodeTest, TwoModifiersOnDifferentFieldsParseSuccessfully) { + auto update = fromjson("{$set: {a: 5, b: 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b"], collator)); +} + +TEST(UpdateObjectNodeTest, TwoModifiersWithSameDottedPathFailToParse) { + auto update = fromjson("{$set: {'a.b': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.b' would create a conflict at 'a.b'"); +} + +TEST(UpdateObjectNodeTest, FirstModifierPrefixOfSecondFailToParse) { + auto update = fromjson("{$set: {a: 5, 'a.b': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.b' would create a conflict at 'a'"); +} + +TEST(UpdateObjectNodeTest, FirstModifierDottedPrefixOfSecondFailsToParse) { + auto update = fromjson("{$set: {'a.b': 5, 'a.b.c': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.b.c' would create a conflict at 'a.b'"); +} + +TEST(UpdateObjectNodeTest, SecondModifierPrefixOfFirstFailsToParse) { + auto update = fromjson("{$set: {'a.b': 5, a: 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), "Updating the path 'a' would create a conflict at 'a'"); +} + +TEST(UpdateObjectNodeTest, SecondModifierDottedPrefixOfFirstFailsToParse) { + auto update = fromjson("{$set: {'a.b.c': 5, 'a.b': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.b' would create a conflict at 'a.b'"); +} + +TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixParseSuccessfully) { + auto update = fromjson("{$set: {'a.b': 5, 'a.c': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.c"], collator)); +} + +TEST(UpdateObjectNodeTest, ModifiersWithCommonDottedPrefixParseSuccessfully) { + auto update = fromjson("{$set: {'a.b.c': 5, 'a.b.d': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.d"], collator)); +} + +TEST(UpdateObjectNodeTest, ModifiersWithCommonPrefixDottedSuffixParseSuccessfully) { + auto update = fromjson("{$set: {'a.b.c': 5, 'a.d.e': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.b.c"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.d.e"], collator)); +} + +TEST(UpdateObjectNodeTest, TwoModifiersOnSamePositionalFieldFailToParse) { + auto update = fromjson("{$set: {'a.$': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.$' would create a conflict at 'a.$'"); +} + +TEST(UpdateObjectNodeTest, PositionalFieldsWithDifferentPrefixesParseSuccessfully) { + auto update = fromjson("{$set: {'a.$': 5, 'b.$': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["b.$"], collator)); +} + +TEST(UpdateObjectNodeTest, PositionalAndNonpositionalFieldWithCommonPrefixParseSuccessfully) { + auto update = fromjson("{$set: {'a.$': 5, 'a.0': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.0"], collator)); +} + +TEST(UpdateObjectNodeTest, TwoModifiersWithSamePositionalDottedPathFailToParse) { + auto update = fromjson("{$set: {'a.$.b': 5}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.$.b' would create a conflict at 'a.$.b'"); +} + +TEST(UpdateObjectNodeTest, FirstModifierPositionalPrefixOfSecondFailsToParse) { + auto update = fromjson("{$set: {'a.$': 5, 'a.$.b': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.$.b' would create a conflict at 'a.$'"); +} + +TEST(UpdateObjectNodeTest, SecondModifierPositionalPrefixOfFirstFailsToParse) { + auto update = fromjson("{$set: {'a.$.b': 5, 'a.$': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$.b"], collator)); + auto result = UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a.$"], collator); + ASSERT_NOT_OK(result); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::ConflictingUpdateOperators); + ASSERT_EQ(result.getStatus().reason(), + "Updating the path 'a.$' would create a conflict at 'a.$'"); +} + +TEST(UpdateObjectNodeTest, FirstModifierFieldPrefixOfSecondParsesSuccessfully) { + auto update = fromjson("{$set: {'a': 5, 'ab': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator)); +} + +TEST(UpdateObjectNodeTest, SecondModifierFieldPrefixOfSecondParsesSuccessfully) { + auto update = fromjson("{$set: {'ab': 5, 'a': 6}}"); + const CollatorInterface* collator = nullptr; + UpdateObjectNode root; + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["ab"], collator)); + ASSERT_OK(UpdateObjectNode::parseAndMerge( + &root, modifiertable::ModifierType::MOD_SET, update["$set"]["a"], collator)); +} + +} // namespace diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp index 429180205fc..c0c692473a6 100644 --- a/src/mongo/dbtests/query_stage_update.cpp +++ b/src/mongo/dbtests/query_stage_update.cpp @@ -47,11 +47,11 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" -#include "mongo/db/ops/update_driver.h" #include "mongo/db/ops/update_lifecycle_impl.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/service_context.h" +#include "mongo/db/update/update_driver.h" #include "mongo/dbtests/dbtests.h" #include "mongo/stdx/memory.h" diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index c5c7e32c73d..badffd70d6f 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -95,10 +95,10 @@ env.Library( '$BUILD_DIR/mongo/client/connection_string', '$BUILD_DIR/mongo/db/common', '$BUILD_DIR/mongo/db/matcher/expressions', - '$BUILD_DIR/mongo/db/ops/update_common', '$BUILD_DIR/mongo/db/query/query_planner', '$BUILD_DIR/mongo/db/query/query_request', '$BUILD_DIR/mongo/db/repl/optime', + '$BUILD_DIR/mongo/db/update/update_common', '$BUILD_DIR/mongo/rpc/metadata', ] ) diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index 3518a7e9cc2..4cef9efdec4 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -37,8 +37,8 @@ #include "mongo/db/hasher.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/extensions_callback_noop.h" -#include "mongo/db/ops/path_support.h" #include "mongo/db/query/canonical_query.h" +#include "mongo/db/update/path_support.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/transitional_tools_do_not_use/vector_spooling.h" |