Skip to content

Commit 6f46bc0

Browse files
authored
CDRIVER-4425 Provide access to raw result if server error occurs (#1144)
1 parent 18cf71f commit 6f46bc0

15 files changed

+895
-26
lines changed

src/libmongoc/src/mongoc/mongoc-error-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ _mongoc_error_is_state_change (bson_error_t *error);
8888
bool
8989
_mongoc_error_is_network (const bson_error_t *error);
9090

91+
bool
92+
_mongoc_error_is_server (const bson_error_t *error);
93+
9194
bool
9295
_mongoc_error_is_auth (const bson_error_t *error);
9396

src/libmongoc/src/mongoc/mongoc-error.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ mongoc_error_has_label (const bson_t *reply, const char *label)
5959
return false;
6060
}
6161

62-
static bool
63-
_mongoc_error_is_server (bson_error_t *error)
62+
bool
63+
_mongoc_error_is_server (const bson_error_t *error)
6464
{
6565
if (!error) {
6666
return false;

src/libmongoc/src/mongoc/mongoc-write-command-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ typedef struct {
8888
* primary, this contains the server id of the newly selected primary. Only
8989
* applies to OP_MSG. Is left at 0 if no retry occurs. */
9090
uint32_t retry_server_id;
91+
/* store the raw server response if an error occured */
92+
uint32_t n_errorReplies;
93+
bson_t rawErrorReplies;
9194
} mongoc_write_result_t;
9295

9396

src/libmongoc/src/mongoc/mongoc-write-command.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ _mongoc_write_result_init (mongoc_write_result_t *result) /* IN */
11471147
bson_init (&result->writeConcernErrors);
11481148
bson_init (&result->writeErrors);
11491149
bson_init (&result->errorLabels);
1150+
bson_init (&result->rawErrorReplies);
11501151

11511152
EXIT;
11521153
}
@@ -1163,6 +1164,7 @@ _mongoc_write_result_destroy (mongoc_write_result_t *result)
11631164
bson_destroy (&result->writeConcernErrors);
11641165
bson_destroy (&result->writeErrors);
11651166
bson_destroy (&result->errorLabels);
1167+
bson_destroy (&result->rawErrorReplies);
11661168

11671169
EXIT;
11681170
}
@@ -1355,6 +1357,22 @@ _mongoc_write_result_merge (mongoc_write_result_t *result, /* IN */
13551357
result->n_writeConcernErrors++;
13561358
}
13571359

1360+
/* If a server error ocurred, then append the raw response to the
1361+
* error_replies array. */
1362+
if (!_mongoc_cmd_check_ok (
1363+
reply, MONGOC_ERROR_API_VERSION_2, NULL /* error */)) {
1364+
char str[16];
1365+
const char *key;
1366+
1367+
bson_uint32_to_string (result->n_errorReplies, &key, str, sizeof str);
1368+
1369+
if (!bson_append_document (&result->rawErrorReplies, key, -1, reply)) {
1370+
MONGOC_ERROR ("Error adding \"%s\" to errorReplies.\n", key);
1371+
}
1372+
1373+
result->n_errorReplies++;
1374+
}
1375+
13581376
/* inefficient if there are ever large numbers: for each label in each err,
13591377
* we linear-search result->errorLabels to see if it's included yet */
13601378
_mongoc_bson_array_copy_labels_to (reply, &result->errorLabels);
@@ -1465,6 +1483,7 @@ _mongoc_write_result_complete (
14651483
/* produce either old fields like nModified from the deprecated Bulk API Spec
14661484
* or new fields like modifiedCount from the CRUD Spec, which we partly obey
14671485
*/
1486+
14681487
if (bson && mongoc_write_concern_is_acknowledged (wc)) {
14691488
n_args = 0;
14701489
va_start (args, error);
@@ -1529,6 +1548,12 @@ _mongoc_write_result_complete (
15291548
}
15301549
}
15311550

1551+
/* If there is a raw error response then we know a server error has occurred.
1552+
* We should add the raw result to the reply. */
1553+
if (bson && !bson_empty (&result->rawErrorReplies)) {
1554+
BSON_APPEND_ARRAY (bson, "errorReplies", &result->rawErrorReplies);
1555+
}
1556+
15321557
/* set bson_error_t from first write error or write concern error */
15331558
_set_error_from_response (
15341559
&result->writeErrors, domain, "write", &result->error);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{
2+
"description": "modifyCollection-errorResponse",
3+
"schemaVersion": "1.12",
4+
"createEntities": [
5+
{
6+
"client": {
7+
"id": "client0",
8+
"observeEvents": [
9+
"commandStartedEvent"
10+
]
11+
}
12+
},
13+
{
14+
"database": {
15+
"id": "database0",
16+
"client": "client0",
17+
"databaseName": "collMod-tests"
18+
}
19+
},
20+
{
21+
"collection": {
22+
"id": "collection0",
23+
"database": "database0",
24+
"collectionName": "test"
25+
}
26+
}
27+
],
28+
"initialData": [
29+
{
30+
"collectionName": "test",
31+
"databaseName": "collMod-tests",
32+
"documents": [
33+
{
34+
"_id": 1,
35+
"x": 1
36+
},
37+
{
38+
"_id": 2,
39+
"x": 1
40+
}
41+
]
42+
}
43+
],
44+
"tests": [
45+
{
46+
"description": "modifyCollection prepareUnique violations are accessible",
47+
"runOnRequirements": [
48+
{
49+
"minServerVersion": "5.2"
50+
}
51+
],
52+
"operations": [
53+
{
54+
"name": "createIndex",
55+
"object": "collection0",
56+
"arguments": {
57+
"keys": {
58+
"x": 1
59+
}
60+
}
61+
},
62+
{
63+
"name": "modifyCollection",
64+
"object": "database0",
65+
"arguments": {
66+
"collection": "test",
67+
"index": {
68+
"keyPattern": {
69+
"x": 1
70+
},
71+
"prepareUnique": true
72+
}
73+
}
74+
},
75+
{
76+
"name": "insertOne",
77+
"object": "collection0",
78+
"arguments": {
79+
"document": {
80+
"_id": 3,
81+
"x": 1
82+
}
83+
},
84+
"expectError": {
85+
"errorCode": 11000
86+
}
87+
},
88+
{
89+
"name": "modifyCollection",
90+
"object": "database0",
91+
"arguments": {
92+
"collection": "test",
93+
"index": {
94+
"keyPattern": {
95+
"x": 1
96+
},
97+
"unique": true
98+
}
99+
},
100+
"expectError": {
101+
"isClientError": false,
102+
"errorCode": 359,
103+
"errorResponse": {
104+
"violations": [
105+
{
106+
"ids": [
107+
1,
108+
2
109+
]
110+
}
111+
]
112+
}
113+
}
114+
}
115+
]
116+
}
117+
]
118+
}
119+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{
2+
"description": "aggregate-merge-errorResponse",
3+
"schemaVersion": "1.12",
4+
"createEntities": [
5+
{
6+
"client": {
7+
"id": "client0"
8+
}
9+
},
10+
{
11+
"database": {
12+
"id": "database0",
13+
"client": "client0",
14+
"databaseName": "crud-tests"
15+
}
16+
},
17+
{
18+
"collection": {
19+
"id": "collection0",
20+
"database": "database0",
21+
"collectionName": "test"
22+
}
23+
}
24+
],
25+
"initialData": [
26+
{
27+
"collectionName": "test",
28+
"databaseName": "crud-tests",
29+
"documents": [
30+
{
31+
"_id": 1,
32+
"x": 1
33+
},
34+
{
35+
"_id": 2,
36+
"x": 1
37+
}
38+
]
39+
}
40+
],
41+
"tests": [
42+
{
43+
"description": "aggregate $merge DuplicateKey error is accessible",
44+
"runOnRequirements": [
45+
{
46+
"minServerVersion": "5.1",
47+
"topologies": [
48+
"single",
49+
"replicaset"
50+
]
51+
}
52+
],
53+
"operations": [
54+
{
55+
"name": "aggregate",
56+
"object": "database0",
57+
"arguments": {
58+
"pipeline": [
59+
{
60+
"$documents": [
61+
{
62+
"_id": 2,
63+
"x": 1
64+
}
65+
]
66+
},
67+
{
68+
"$merge": {
69+
"into": "test",
70+
"whenMatched": "fail"
71+
}
72+
}
73+
]
74+
},
75+
"expectError": {
76+
"errorCode": 11000,
77+
"errorResponse": {
78+
"keyPattern": {
79+
"_id": 1
80+
},
81+
"keyValue": {
82+
"_id": 2
83+
}
84+
}
85+
}
86+
}
87+
]
88+
}
89+
]
90+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
"description": "bulkWrite-errorResponse",
3+
"schemaVersion": "1.12",
4+
"createEntities": [
5+
{
6+
"client": {
7+
"id": "client0",
8+
"useMultipleMongoses": false
9+
}
10+
},
11+
{
12+
"database": {
13+
"id": "database0",
14+
"client": "client0",
15+
"databaseName": "crud-tests"
16+
}
17+
},
18+
{
19+
"collection": {
20+
"id": "collection0",
21+
"database": "database0",
22+
"collectionName": "test"
23+
}
24+
}
25+
],
26+
"tests": [
27+
{
28+
"description": "bulkWrite operations support errorResponse assertions",
29+
"runOnRequirements": [
30+
{
31+
"minServerVersion": "4.0.0",
32+
"topologies": [
33+
"single",
34+
"replicaset"
35+
]
36+
},
37+
{
38+
"minServerVersion": "4.2.0",
39+
"topologies": [
40+
"sharded"
41+
]
42+
}
43+
],
44+
"operations": [
45+
{
46+
"name": "failPoint",
47+
"object": "testRunner",
48+
"arguments": {
49+
"client": "client0",
50+
"failPoint": {
51+
"configureFailPoint": "failCommand",
52+
"mode": {
53+
"times": 1
54+
},
55+
"data": {
56+
"failCommands": [
57+
"insert"
58+
],
59+
"errorCode": 8
60+
}
61+
}
62+
}
63+
},
64+
{
65+
"name": "bulkWrite",
66+
"object": "collection0",
67+
"arguments": {
68+
"requests": [
69+
{
70+
"insertOne": {
71+
"document": {
72+
"_id": 1
73+
}
74+
}
75+
}
76+
]
77+
},
78+
"expectError": {
79+
"errorCode": 8,
80+
"errorResponse": {
81+
"code": 8
82+
}
83+
}
84+
}
85+
]
86+
}
87+
]
88+
}
89+

0 commit comments

Comments
 (0)