Skip to content

Commit ebd74c8

Browse files
committed
CDRIVER-5969 return NULL result if no writes indicated (#1990)
1 parent 5849a9d commit ebd74c8

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
@@ -865,6 +865,9 @@ struct _mongoc_bulkwriteresult_t {
865865
bson_t updateresults;
866866
bson_t deleteresults;
867867
bool verboseresults;
868+
// `parsed_some_results` becomes true if an ok:1 reply to `bulkWrite` is successfully parsed.
869+
// Used to determine whether some writes were successful.
870+
bool parsed_some_results;
868871
};
869872

870873
int64_t
@@ -1334,6 +1337,8 @@ _bulkwritereturn_apply_reply (mongoc_bulkwritereturn_t *self, const bson_t *cmd_
13341337
_bulkwriteexception_append_writeconcernerror (self->exc, code, errmsg, &errInfo);
13351338
}
13361339

1340+
self->res->parsed_some_results = true;
1341+
13371342
return true;
13381343
}
13391344

@@ -1514,6 +1519,7 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
15141519
BSON_ASSERT_PARAM (self);
15151520
BSON_OPTIONAL_PARAM (opts);
15161521

1522+
// `has_successful_results` is set to true if any `bulkWrite` reply indicates some writes succeeded.
15171523
bool has_successful_results = false;
15181524
mongoc_bulkwritereturn_t ret = {0};
15191525
bson_error_t error = {0};
@@ -1945,16 +1951,18 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
19451951
}
19461952

19471953
fail:
1948-
if (is_ordered) {
1949-
// Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded.
1950-
if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) {
1951-
has_successful_results = true;
1952-
}
1953-
} else {
1954-
BSON_ASSERT (mlib_in_range (size_t, ret.res->errorscount));
1955-
size_t errorscount_sz = (size_t) ret.res->errorscount;
1956-
if (errorscount_sz < self->n_ops) {
1957-
has_successful_results = true;
1954+
if (ret.res->parsed_some_results) {
1955+
if (is_ordered) {
1956+
// Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded.
1957+
if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) {
1958+
has_successful_results = true;
1959+
}
1960+
} else {
1961+
BSON_ASSERT (mlib_in_range (size_t, ret.res->errorscount));
1962+
size_t errorscount_sz = (size_t) ret.res->errorscount;
1963+
if (errorscount_sz < self->n_ops) {
1964+
has_successful_results = true;
1965+
}
19581966
}
19591967
}
19601968
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
@@ -367,8 +367,8 @@ prose_test_4 (void *ctx)
367367
}
368368

369369
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, NULL /* options */);
370-
ASSERT_NO_BULKWRITEEXCEPTION (ret);
371370
ASSERT (ret.res);
371+
ASSERT_NO_BULKWRITEEXCEPTION (ret);
372372
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (ret.res), ==, numModels);
373373
mongoc_bulkwriteexception_destroy (ret.exc);
374374
mongoc_bulkwriteresult_destroy (ret.res);
@@ -466,6 +466,7 @@ prose_test_5 (void *ctx)
466466
}
467467

468468
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, NULL /* options */);
469+
ASSERT (ret.res); // Has partial results.
469470
ASSERT (ret.exc);
470471

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

541543
if (mongoc_bulkwriteexception_error (ret.exc, &error)) {
@@ -575,6 +577,7 @@ prose_test_6 (void *ctx)
575577
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
576578
mongoc_bulkwriteopts_set_ordered (opts, true);
577579
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
580+
ASSERT (!ret.res); // No result due to no successful writes.
578581
ASSERT (ret.exc);
579582

580583
if (mongoc_bulkwriteexception_error (ret.exc, &error)) {
@@ -656,7 +659,7 @@ prose_test_7 (void *ctx)
656659
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
657660
mongoc_bulkwriteopts_set_verboseresults (opts, true);
658661
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
659-
662+
ASSERT (ret.res);
660663
ASSERT_NO_BULKWRITEEXCEPTION (ret);
661664

662665
ASSERT_CMPINT64 (mongoc_bulkwriteresult_upsertedcount (ret.res), ==, 2);
@@ -742,7 +745,7 @@ prose_test_8 (void *ctx)
742745
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
743746
mongoc_bulkwriteopts_set_verboseresults (opts, true);
744747
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
745-
748+
ASSERT (ret.res);
746749
ASSERT_NO_BULKWRITEEXCEPTION (ret);
747750

748751
ASSERT_CMPINT64 (mongoc_bulkwriteresult_upsertedcount (ret.res), ==, 2);
@@ -843,13 +846,13 @@ prose_test_9 (void *ctx)
843846
mongoc_bulkwriteopts_t *opts = mongoc_bulkwriteopts_new ();
844847
mongoc_bulkwriteopts_set_verboseresults (opts, true);
845848
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
849+
ASSERT (ret.res);
846850
ASSERT (ret.exc);
847851

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

855858
// Check length of update results.
@@ -912,12 +915,12 @@ prose_test_10 (void *ctx)
912915
ASSERT_OR_PRINT (ok, error);
913916

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

932935
mongoc_bulkwritereturn_t ret = mongoc_bulkwrite_execute (bw, opts);
936+
ASSERT (!ret.res); // No result due to unacknowledged write concern.
933937
ASSERT (ret.exc);
934938
if (!mongoc_bulkwriteexception_error (ret.exc, &error)) {
935939
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (ret.exc));
936940
}
937941
ASSERT_ERROR_CONTAINS (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "of size");
938-
939942
mongoc_bulkwriteexception_destroy (ret.exc);
940943
mongoc_bulkwriteresult_destroy (ret.res);
941944
mongoc_bulkwrite_destroy (bw);
@@ -1076,6 +1079,7 @@ prose_test_11 (void *ctx)
10761079
// Execute.
10771080
{
10781081
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (tf->bw, NULL /* opts */);
1082+
ASSERT (bwr.res);
10791083
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
10801084
ASSERT (mlib_in_range (int64_t, tf->numModels));
10811085
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (bwr.res), ==, (int64_t) tf->numModels + 1);
@@ -1126,6 +1130,7 @@ prose_test_11 (void *ctx)
11261130
// Execute.
11271131
{
11281132
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (tf->bw, NULL /* opts */);
1133+
ASSERT (bwr.res);
11291134
ASSERT_NO_BULKWRITEEXCEPTION (bwr);
11301135
ASSERT (mlib_in_range (int64_t, tf->numModels));
11311136
ASSERT_CMPINT64 (mongoc_bulkwriteresult_insertedcount (bwr.res), ==, (int64_t) tf->numModels + 1);
@@ -1206,6 +1211,7 @@ prose_test_12 (void *ctx)
12061211
// Execute.
12071212
{
12081213
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1214+
ASSERT (!bwr.res); // No result due to no successful writes.
12091215
ASSERT (bwr.exc);
12101216
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12111217
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));
@@ -1234,6 +1240,7 @@ prose_test_12 (void *ctx)
12341240
// Execute.
12351241
{
12361242
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1243+
ASSERT (!bwr.res); // No result due to no successful writes.
12371244
ASSERT (bwr.exc);
12381245
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12391246
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));
@@ -1283,6 +1290,7 @@ prose_test_13 (void *ctx)
12831290
// Execute.
12841291
{
12851292
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, NULL);
1293+
ASSERT (!bwr.res); // No result due to no successful writes.
12861294
ASSERT (bwr.exc);
12871295
if (!mongoc_bulkwriteexception_error (bwr.exc, &error)) {
12881296
test_error ("Expected top-level error but got:\n%s", test_bulkwriteexception_str (bwr.exc));

0 commit comments

Comments
 (0)