diff --git a/src/libmongoc/src/mongoc/mongoc-array-private.h b/src/libmongoc/src/mongoc/mongoc-array-private.h index 9956224b347..c8de6f1f526 100644 --- a/src/libmongoc/src/mongoc/mongoc-array-private.h +++ b/src/libmongoc/src/mongoc/mongoc-array-private.h @@ -25,6 +25,9 @@ BSON_BEGIN_DECLS +// mongoc_array_t stores an array of objects of type T. +// +// T must be trivially relocatable. In particular, `bson_t` is not trivially relocatable (CDRIVER-6113). typedef struct _mongoc_array_t mongoc_array_t; diff --git a/src/libmongoc/src/mongoc/mongoc-write-command-private.h b/src/libmongoc/src/mongoc/mongoc-write-command-private.h index a45d0638bac..c5a7193b683 100644 --- a/src/libmongoc/src/mongoc/mongoc-write-command-private.h +++ b/src/libmongoc/src/mongoc/mongoc-write-command-private.h @@ -62,7 +62,7 @@ typedef struct { uint32_t n_documents; mongoc_bulk_write_flags_t flags; int64_t operation_id; - bson_t cmd_opts; + bson_t *cmd_opts; } mongoc_write_command_t; diff --git a/src/libmongoc/src/mongoc/mongoc-write-command.c b/src/libmongoc/src/mongoc/mongoc-write-command.c index 993892b6f39..9d65a29518f 100644 --- a/src/libmongoc/src/mongoc/mongoc-write-command.c +++ b/src/libmongoc/src/mongoc/mongoc-write-command.c @@ -144,9 +144,9 @@ _mongoc_write_command_init_bulk ( command->flags = flags; command->operation_id = operation_id; if (!bson_empty0 (opts)) { - bson_copy_to (opts, &command->cmd_opts); + command->cmd_opts = bson_copy (opts); } else { - bson_init (&command->cmd_opts); + command->cmd_opts = bson_new (); } _mongoc_buffer_init (&command->payload, NULL, 0, NULL, NULL); @@ -668,7 +668,7 @@ _mongoc_write_opmsg (mongoc_write_command_t *command, ? MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_NO : MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES; - BSON_ASSERT (bson_iter_init (&iter, &command->cmd_opts)); + BSON_ASSERT (bson_iter_init (&iter, command->cmd_opts)); if (!mongoc_cmd_parts_append_opts (&parts, &iter, error)) { bson_destroy (&cmd); mongoc_cmd_parts_cleanup (&parts); @@ -937,7 +937,7 @@ _mongoc_write_command_destroy (mongoc_write_command_t *command) ENTRY; if (command) { - bson_destroy (&command->cmd_opts); + bson_destroy (command->cmd_opts); _mongoc_buffer_destroy (&command->payload); } diff --git a/src/libmongoc/tests/test-mongoc-bulk.c b/src/libmongoc/tests/test-mongoc-bulk.c index f62e590b2c1..80d6bfd7371 100644 --- a/src/libmongoc/tests/test-mongoc-bulk.c +++ b/src/libmongoc/tests/test-mongoc-bulk.c @@ -4807,6 +4807,54 @@ test_multiple_execution (void) mongoc_client_destroy (client); } +// `test_bulk_big_let` tests a bulk operation with a large let document to reproduce CDRIVER-6112: +static void +test_bulk_big_let (void *unused) +{ + BSON_UNUSED (unused); + + mongoc_client_t *client = test_framework_new_default_client (); + mongoc_collection_t *coll = get_test_collection (client, "test_big_let"); + bson_error_t error; + + // Create bulk operation similar to PHP driver: + mongoc_bulk_operation_t *bulk = mongoc_bulk_operation_new (true /* ordered */); + + // Set a large `let`: { "testDocument": { "a": "aaa..." } } + { + bson_t let = BSON_INITIALIZER, testDocument; + bson_append_document_begin (&let, "testDocument", -1, &testDocument); + + // Append big string: + { + size_t num_chars = 79; + char *big_string = bson_malloc0 (num_chars + 1); + memset (big_string, 'a', num_chars); + BSON_APPEND_UTF8 (&testDocument, "a", big_string); + bson_free (big_string); + } + + bson_append_document_end (&let, &testDocument); + mongoc_bulk_operation_set_let (bulk, &let); + bson_destroy (&let); + } + + + mongoc_bulk_operation_set_client (bulk, client); + mongoc_bulk_operation_set_database (bulk, "db"); + mongoc_bulk_operation_set_collection (bulk, "coll"); + + mongoc_bulk_operation_update ( + bulk, tmp_bson ("{'_id': 1}"), tmp_bson ("{'$set': {'document': '$$testDocument'}}"), true); + + + ASSERT_OR_PRINT (mongoc_bulk_operation_execute (bulk, NULL, &error), error); + + mongoc_bulk_operation_destroy (bulk); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); +} + void test_bulk_install (TestSuite *suite) @@ -4985,4 +5033,11 @@ test_bulk_install (TestSuite *suite) "/BulkOperation/set_client_updates_operation_id_when_client_changes", test_bulk_write_set_client_updates_operation_id_when_client_changes); TestSuite_AddLive (suite, "/BulkOperation/multiple_execution", test_multiple_execution); + TestSuite_AddFull ( + suite, + "/BulkOperation/big_let", + test_bulk_big_let, + NULL, + NULL, + test_framework_skip_if_max_wire_version_less_than_13 /* 5.0+ for 'let' support in CRUD commands */); }