Skip to content

Commit 44df408

Browse files
committed
CDRIVER-5969 return NULL result if no writes indicated (#1990)
1 parent df388b3 commit 44df408

File tree

3 files changed

+84
-17
lines changed

3 files changed

+84
-17
lines changed

src/libmongoc/src/mongoc/mongoc-bulkwrite.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,9 @@ struct _mongoc_bulkwriteresult_t {
863863
bson_t updateresults;
864864
bson_t deleteresults;
865865
bool verboseresults;
866+
// `parsed_some_results` becomes true if an ok:1 reply to `bulkWrite` is successfully parsed.
867+
// Used to determine whether some writes were successful.
868+
bool parsed_some_results;
866869
};
867870

868871
int64_t
@@ -1332,6 +1335,8 @@ _bulkwritereturn_apply_reply (mongoc_bulkwritereturn_t *self, const bson_t *cmd_
13321335
_bulkwriteexception_append_writeconcernerror (self->exc, code, errmsg, &errInfo);
13331336
}
13341337

1338+
self->res->parsed_some_results = true;
1339+
13351340
return true;
13361341
}
13371342

@@ -1512,6 +1517,7 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
15121517
BSON_ASSERT_PARAM (self);
15131518
BSON_OPTIONAL_PARAM (opts);
15141519

1520+
// `has_successful_results` is set to true if any `bulkWrite` reply indicates some writes succeeded.
15151521
bool has_successful_results = false;
15161522
mongoc_bulkwritereturn_t ret = {0};
15171523
bson_error_t error = {0};
@@ -1946,16 +1952,18 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
19461952
}
19471953

19481954
fail:
1949-
if (is_ordered) {
1950-
// Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded.
1951-
if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) {
1952-
has_successful_results = true;
1953-
}
1954-
} else {
1955-
BSON_ASSERT (mcommon_in_range_size_t_signed (ret.res->errorscount));
1956-
size_t errorscount_sz = (size_t) ret.res->errorscount;
1957-
if (errorscount_sz < self->n_ops) {
1958-
has_successful_results = true;
1955+
if (ret.res->parsed_some_results) {
1956+
if (is_ordered) {
1957+
// Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded.
1958+
if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) {
1959+
has_successful_results = true;
1960+
}
1961+
} else {
1962+
BSON_ASSERT (mcommon_in_range_size_t_signed (ret.res->errorscount));
1963+
size_t errorscount_sz = (size_t) ret.res->errorscount;
1964+
if (errorscount_sz < self->n_ops) {
1965+
has_successful_results = true;
1966+
}
19591967
}
19601968
}
19611969
if (!is_acknowledged || !has_successful_results) {

src/libmongoc/tests/test-mongoc-bulkwrite.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ test_bulkwrite_double_execute (void *ctx)
219219
// Execute.
220220
{
221221
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
222+
ASSERT (bwr.res);
222223
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
223224
mongoc_bulkwriteresult_destroy (bwr.res);
224225
mongoc_bulkwriteexception_destroy (bwr.exc);
@@ -251,6 +252,7 @@ test_bulkwrite_double_execute (void *ctx)
251252

252253
{
253254
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
255+
ASSERT (!bwr.res); // No result due to no successful writes.
254256
ASSERT (bwr.exc);
255257
ASSERT (mongoc_bulkwriteexception_error (bwr.exc, &error));
256258
ASSERT_ERROR_CONTAINS (
@@ -309,6 +311,7 @@ test_bulkwrite_serverid (void *ctx)
309311
// Execute.
310312
{
311313
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, bwo);
314+
ASSERT (bwr.res);
312315
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
313316
// Expect the selected server is reported as used.
314317
uint32_t used_serverid = mongoc_bulkwriteresult_serverid (bwr.res);
@@ -381,6 +384,7 @@ test_bulkwrite_serverid_on_retry (void *ctx)
381384
// Execute.
382385
{
383386
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, bwo);
387+
ASSERT (bwr.res);
384388
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
385389
// Expect a different server was used due to retry.
386390
uint32_t used_serverid = mongoc_bulkwriteresult_serverid (bwr.res);
@@ -444,6 +448,7 @@ test_bulkwrite_extra (void *ctx)
444448
// Execute.
445449
{
446450
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, bwo);
451+
ASSERT (bwr.res);
447452
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
448453
mongoc_bulkwriteresult_destroy (bwr.res);
449454
mongoc_bulkwriteexception_destroy (bwr.exc);
@@ -486,6 +491,7 @@ test_bulkwrite_no_verbose_results (void *ctx)
486491
// Execute.
487492
{
488493
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL /* opts */);
494+
ASSERT (bwr.res);
489495
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
490496
// Expect no verbose results.
491497
ASSERT (NULL == mongoc_bulkwriteresult_insertresults (bwr.res));
@@ -558,6 +564,7 @@ test_bulkwrite_many_namespaces (void *ctx)
558564
// Execute.
559565
{
560566
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL /* opts */);
567+
ASSERT (bwr.res);
561568
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
562569
mongoc_bulkwriteresult_destroy (bwr.res);
563570
mongoc_bulkwriteexception_destroy (bwr.exc);
@@ -606,6 +613,7 @@ test_bulkwrite_execute_requires_client (void *ctx)
606613
// Attempt execution without assigning a client
607614
{
608615
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
616+
ASSERT (!bwr.res); // No result due to no successful writes.
609617
ASSERT (bwr.exc);
610618
ASSERT (mongoc_bulkwriteexception_error (bwr.exc, &error));
611619
ASSERT_ERROR_CONTAINS (error,
@@ -620,6 +628,7 @@ test_bulkwrite_execute_requires_client (void *ctx)
620628
{
621629
mongoc_bulkwrite_set_client (bw, client);
622630
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
631+
ASSERT (bwr.res);
623632
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
624633
mongoc_bulkwriteresult_destroy (bwr.res);
625634
mongoc_bulkwriteexception_destroy (bwr.exc);
@@ -667,8 +676,8 @@ test_bulkwrite_two_large_inserts (void *unused)
667676
ASSERT_OR_PRINT (mongoc_bulkwrite_append_insertone (bw, "db.coll", docs[1], NULL, &error), error);
668677

669678
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, bw_opts);
670-
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
671679
ASSERT (bwr.res);
680+
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
672681
const bson_t *insertresults = mongoc_bulkwriteresult_insertresults (bwr.res);
673682
ASSERT_MATCH (insertresults,
674683
BSON_STR ({"0" : {"insertedId" : "over_2mib_1"}}, {"1" : {"insertedId" : "over_2mib_2"}}));
@@ -682,6 +691,40 @@ test_bulkwrite_two_large_inserts (void *unused)
682691
bson_free (large_string);
683692
}
684693

694+
695+
// `test_bulkwrite_client_error_no_result` is a regression test for CDRIVER-5969.
696+
static void
697+
test_bulkwrite_client_error_no_result (void *unused)
698+
{
699+
BSON_UNUSED (unused);
700+
701+
bson_error_t error;
702+
mongoc_client_t *client = test_framework_new_default_client ();
703+
// Trigger a client-side error by adding a too-big document.
704+
{
705+
mongoc_bulkwrite_t *bw = mongoc_client_bulkwrite_new (client);
706+
bson_t too_big = BSON_INITIALIZER;
707+
const size_t maxMessageSizeByte = 48000000;
708+
char *big_string = bson_malloc (maxMessageSizeByte + 1);
709+
memset (big_string, 'a', maxMessageSizeByte);
710+
big_string[maxMessageSizeByte] = '\0';
711+
BSON_APPEND_UTF8 (&too_big, "big", big_string);
712+
ASSERT_OR_PRINT (mongoc_bulkwrite_append_insertone (bw, "db.coll", &too_big, NULL, &error), error);
713+
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
714+
ASSERT (!bwr.res); // No result due to no successful writes.
715+
ASSERT (bwr.exc);
716+
ASSERT (mongoc_bulkwriteexception_error (bwr.exc, &error));
717+
ASSERT_ERROR_CONTAINS (
718+
error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Sending would exceed maxMessageSizeBytes");
719+
bson_free (big_string);
720+
bson_destroy (&too_big);
721+
mongoc_bulkwriteresult_destroy (bwr.res);
722+
mongoc_bulkwriteexception_destroy (bwr.exc);
723+
mongoc_bulkwrite_destroy (bw);
724+
}
725+
726+
mongoc_client_destroy (client);
727+
}
685728
void
686729
test_bulkwrite_install (TestSuite *suite)
687730
{
@@ -783,4 +826,12 @@ test_bulkwrite_install (TestSuite *suite)
783826
NULL /* ctx */,
784827
test_framework_skip_if_max_wire_version_less_than_25 // require server 8.0
785828
);
829+
830+
TestSuite_AddFull (suite,
831+
"/bulkwrite/client_error_no_result",
832+
test_bulkwrite_client_error_no_result,
833+
NULL /* dtor */,
834+
NULL /* ctx */,
835+
test_framework_skip_if_max_wire_version_less_than_25 // require server 8.0
836+
);
786837
}

src/libmongoc/tests/test-mongoc-crud.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,8 @@ prose_test_4 (void *ctx)
366366
}
367367

368368
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, NULL /* options */);
369-
ASSERT_NO_BULKWRITEEXCEPTION (ret);
370369
ASSERT (ret.res);
370+
ASSERT_NO_BULKWRITEEXCEPTION (ret);
371371
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (ret.res), ==, numModels);
372372
mongoc_bulkwriteexception_destroy (ret.exc);
373373
mongoc_bulkwriteresult_destroy (ret.res);
@@ -465,6 +465,7 @@ prose_test_5 (void *ctx)
465465
}
466466

467467
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, NULL /* options */);
468+
ASSERT (ret.res); // Has partial results.
468469
ASSERT (ret.exc);
469470

470471
// Expect no top-level error.
@@ -535,6 +536,7 @@ prose_test_6 (void *ctx)
535536
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
536537
mongoc_bulkwriteopts_set_ordered (opts, false);
537538
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
539+
ASSERT (!ret.res); // No result due to no successful writes.
538540
ASSERT (ret.exc);
539541

540542
if (mongoc_bulkwriteexception_error (ret.exc, &error)) {
@@ -574,6 +576,7 @@ prose_test_6 (void *ctx)
574576
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
575577
mongoc_bulkwriteopts_set_ordered (opts, true);
576578
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
579+
ASSERT (!ret.res); // No result due to no successful writes.
577580
ASSERT (ret.exc);
578581

579582
if (mongoc_bulkwriteexception_error (ret.exc, &error)) {
@@ -655,7 +658,7 @@ prose_test_7 (void *ctx)
655658
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
656659
mongoc_bulkwriteopts_set_verboseresults (opts, true);
657660
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
658-
661+
ASSERT (ret.res);
659662
ASSERT_NO_BULKWRITEEXCEPTION (ret);
660663

661664
ASSERT_CMPINT64 (mongoc_bulkwriteresult_upsertedcount (ret.res), ==, 2);
@@ -741,7 +744,7 @@ prose_test_8 (void *ctx)
741744
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
742745
mongoc_bulkwriteopts_set_verboseresults (opts, true);
743746
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
744-
747+
ASSERT (ret.res);
745748
ASSERT_NO_BULKWRITEEXCEPTION (ret);
746749

747750
ASSERT_CMPINT64 (mongoc_bulkwriteresult_upsertedcount (ret.res), ==, 2);
@@ -842,13 +845,13 @@ prose_test_9 (void *ctx)
842845
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
843846
mongoc_bulkwriteopts_set_verboseresults (opts, true);
844847
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
848+
ASSERT (ret.res);
845849
ASSERT (ret.exc);
846850

847851
if (!mongoc_bulkwriteexception_error (ret.exc, &error)) {
848852
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (ret.exc));
849853
}
850854
ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_QUERY, 8, "Failing command via 'failCommand' failpoint");
851-
ASSERT (ret.res);
852855
ASSERT_CMPSIZE_T ((size_t) mongoc_bulkwriteresult_upsertedcount (ret.res), ==, numModels);
853856

854857
// Check length of update results.
@@ -911,12 +914,12 @@ prose_test_10 (void *ctx)
911914
ASSERT_OR_PRINT (ok, error);
912915

913916
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
917+
ASSERT (!ret.res); // No result due to unacknowledged write concern.
914918
ASSERT (ret.exc);
915919
if (!mongoc_bulkwriteexception_error (ret.exc, &error)) {
916920
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (ret.exc));
917921
}
918922
ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "of size");
919-
920923
mongoc_bulkwriteexception_destroy (ret.exc);
921924
mongoc_bulkwriteresult_destroy (ret.res);
922925
mongoc_bulkwrite_destroy (bw);
@@ -929,12 +932,12 @@ prose_test_10 (void *ctx)
929932
ASSERT_OR_PRINT (ok, error);
930933

931934
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
935+
ASSERT (!ret.res); // No result due to unacknowledged write concern.
932936
ASSERT (ret.exc);
933937
if (!mongoc_bulkwriteexception_error (ret.exc, &error)) {
934938
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (ret.exc));
935939
}
936940
ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "of size");
937-
938941
mongoc_bulkwriteexception_destroy (ret.exc);
939942
mongoc_bulkwriteresult_destroy (ret.res);
940943
mongoc_bulkwrite_destroy (bw);
@@ -1075,6 +1078,7 @@ prose_test_11 (void *ctx)
10751078
// Execute.
10761079
{
10771080
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (tf->bw, NULL /* opts */);
1081+
ASSERT (bwr.res);
10781082
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
10791083
ASSERT (mcommon_in_range_int64_t_unsigned (tf->numModels));
10801084
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (bwr.res), ==, (int64_t) tf->numModels + 1);
@@ -1125,6 +1129,7 @@ prose_test_11 (void *ctx)
11251129
// Execute.
11261130
{
11271131
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (tf->bw, NULL /* opts */);
1132+
ASSERT (bwr.res);
11281133
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
11291134
ASSERT (mcommon_in_range_int64_t_unsigned (tf->numModels));
11301135
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (bwr.res), ==, (int64_t) tf->numModels + 1);
@@ -1205,6 +1210,7 @@ prose_test_12 (void *ctx)
12051210
// Execute.
12061211
{
12071212
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1213+
ASSERT (!bwr.res); // No result due to no successful writes.
12081214
ASSERT (bwr.exc);
12091215
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12101216
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));
@@ -1233,6 +1239,7 @@ prose_test_12 (void *ctx)
12331239
// Execute.
12341240
{
12351241
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1242+
ASSERT (!bwr.res); // No result due to no successful writes.
12361243
ASSERT (bwr.exc);
12371244
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12381245
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));
@@ -1282,6 +1289,7 @@ prose_test_13 (void *ctx)
12821289
// Execute.
12831290
{
12841291
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1292+
ASSERT (!bwr.res); // No result due to no successful writes.
12851293
ASSERT (bwr.exc);
12861294
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12871295
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));

0 commit comments

Comments
 (0)