void _mongoc_write_command_init_bulk (mongoc_write_command_t *command, int type, mongoc_bulk_write_flags_t flags, int64_t operation_id, const bson_t *opts) { ENTRY; BSON_ASSERT (command); command->type = type; command->flags = flags; command->operation_id = operation_id; if (!bson_empty0 (opts)) { bson_copy_to (opts, &command->cmd_opts); } else { bson_init (&command->cmd_opts); } _mongoc_buffer_init (&command->payload, NULL, 0, NULL, NULL); command->n_documents = 0; EXIT; }
/* * If error is not set, set code from first document in array like * [{"code": 64, "errmsg": "duplicate"}, ...]. Format the error message * from all errors in array. */ static void _set_error_from_response (bson_t *bson_array, mongoc_error_domain_t domain, const char *error_type, bson_error_t *error /* OUT */) { bson_iter_t array_iter; bson_iter_t doc_iter; bson_string_t *compound_err; const char *errmsg = NULL; int32_t code = 0; uint32_t n_keys, i; compound_err = bson_string_new (NULL); n_keys = bson_count_keys (bson_array); if (n_keys > 1) { bson_string_append_printf ( compound_err, "Multiple %s errors: ", error_type); } if (!bson_empty0 (bson_array) && bson_iter_init (&array_iter, bson_array)) { /* get first code and all error messages */ i = 0; while (bson_iter_next (&array_iter)) { if (BSON_ITER_HOLDS_DOCUMENT (&array_iter) && bson_iter_recurse (&array_iter, &doc_iter)) { /* parse doc, which is like {"code": 64, "errmsg": "duplicate"} */ while (bson_iter_next (&doc_iter)) { /* use the first error code we find */ if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) { code = bson_iter_int32 (&doc_iter); } else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) { errmsg = bson_iter_utf8 (&doc_iter, NULL); /* build message like 'Multiple write errors: "foo", "bar"' */ if (n_keys > 1) { bson_string_append_printf (compound_err, "\"%s\"", errmsg); if (i < n_keys - 1) { bson_string_append (compound_err, ", "); } } else { /* single error message */ bson_string_append (compound_err, errmsg); } } } i++; } } if (code && compound_err->len) { bson_set_error ( error, domain, (uint32_t) code, "%s", compound_err->str); } } bson_string_free (compound_err, true); }
bool _mongoc_write_result_complete (mongoc_write_result_t *result, bson_t *bson, bson_error_t *error) { ENTRY; BSON_ASSERT (result); if (bson) { BSON_APPEND_INT32 (bson, "nInserted", result->nInserted); BSON_APPEND_INT32 (bson, "nMatched", result->nMatched); if (!result->omit_nModified) { BSON_APPEND_INT32 (bson, "nModified", result->nModified); } BSON_APPEND_INT32 (bson, "nRemoved", result->nRemoved); BSON_APPEND_INT32 (bson, "nUpserted", result->nUpserted); if (!bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, "upserted", &result->upserted); } BSON_APPEND_ARRAY (bson, "writeErrors", &result->writeErrors); if (result->n_writeConcernErrors) { BSON_APPEND_ARRAY (bson, "writeConcernErrors", &result->writeConcernErrors); } } /* set bson_error_t from first write error or write concern error */ _set_error_from_response (&result->writeErrors, MONGOC_ERROR_COMMAND, "write", &result->error); if (!result->error.code) { _set_error_from_response (&result->writeConcernErrors, MONGOC_ERROR_WRITE_CONCERN, "write concern", &result->error); } if (error) { memcpy (error, &result->error, sizeof *error); } RETURN (!result->failed && result->error.code == 0); }
/* complete a write result, including only certain fields */ bool _mongoc_write_result_complete ( mongoc_write_result_t *result, /* IN */ int32_t error_api_version, /* IN */ const mongoc_write_concern_t *wc, /* IN */ mongoc_error_domain_t err_domain_override, /* IN */ bson_t *bson, /* OUT */ bson_error_t *error, /* OUT */ ...) { mongoc_error_domain_t domain; va_list args; const char *field; int n_args; bson_iter_t iter; bson_iter_t child; ENTRY; BSON_ASSERT (result); if (error_api_version >= MONGOC_ERROR_API_VERSION_2) { domain = MONGOC_ERROR_SERVER; } else if (err_domain_override) { domain = err_domain_override; } else if (result->error.domain) { domain = (mongoc_error_domain_t) result->error.domain; } else { domain = MONGOC_ERROR_COLLECTION; } /* produce either old fields like nModified from the deprecated Bulk API Spec * or new fields like modifiedCount from the CRUD Spec, which we partly obey */ if (bson && mongoc_write_concern_is_acknowledged (wc)) { n_args = 0; va_start (args, error); while ((field = va_arg (args, const char *))) { n_args++; if (!strcmp (field, "nInserted")) { BSON_APPEND_INT32 (bson, field, result->nInserted); } else if (!strcmp (field, "insertedCount")) { BSON_APPEND_INT32 (bson, field, result->nInserted); } else if (!strcmp (field, "nMatched")) { BSON_APPEND_INT32 (bson, field, result->nMatched); } else if (!strcmp (field, "matchedCount")) { BSON_APPEND_INT32 (bson, field, result->nMatched); } else if (!strcmp (field, "nModified")) { BSON_APPEND_INT32 (bson, field, result->nModified); } else if (!strcmp (field, "modifiedCount")) { BSON_APPEND_INT32 (bson, field, result->nModified); } else if (!strcmp (field, "nRemoved")) { BSON_APPEND_INT32 (bson, field, result->nRemoved); } else if (!strcmp (field, "deletedCount")) { BSON_APPEND_INT32 (bson, field, result->nRemoved); } else if (!strcmp (field, "nUpserted")) { BSON_APPEND_INT32 (bson, field, result->nUpserted); } else if (!strcmp (field, "upsertedCount")) { BSON_APPEND_INT32 (bson, field, result->nUpserted); } else if (!strcmp (field, "upserted") && !bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, field, &result->upserted); } else if (!strcmp (field, "upsertedId") && !bson_empty0 (&result->upserted) && bson_iter_init_find (&iter, &result->upserted, "0") && bson_iter_recurse (&iter, &child) && bson_iter_find (&child, "_id")) { /* "upsertedId", singular, for update_one() */ BSON_APPEND_VALUE (bson, "upsertedId", bson_iter_value (&child)); } } va_end (args); /* default: a standard result includes all Bulk API fields */ if (!n_args) { BSON_APPEND_INT32 (bson, "nInserted", result->nInserted); BSON_APPEND_INT32 (bson, "nMatched", result->nMatched); BSON_APPEND_INT32 (bson, "nModified", result->nModified); BSON_APPEND_INT32 (bson, "nRemoved", result->nRemoved); BSON_APPEND_INT32 (bson, "nUpserted", result->nUpserted); if (!bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, "upserted", &result->upserted); } } /* always append errors if there are any */ if (!n_args || !bson_empty (&result->writeErrors)) { BSON_APPEND_ARRAY (bson, "writeErrors", &result->writeErrors); } if (result->n_writeConcernErrors) { BSON_APPEND_ARRAY ( bson, "writeConcernErrors", &result->writeConcernErrors); } }
/* Update result with the read prefs, following Server Selection Spec. * The driver must have discovered the server is a mongos. */ static void _apply_read_preferences_mongos (const mongoc_read_prefs_t *read_prefs, const bson_t *query_bson, mongoc_apply_read_prefs_result_t *result /* OUT */) { mongoc_read_mode_t mode; const bson_t *tags = NULL; bson_t child; const char *mode_str; mode = mongoc_read_prefs_get_mode (read_prefs); if (read_prefs) { tags = mongoc_read_prefs_get_tags (read_prefs); } /* Server Selection Spec says: * * For mode 'primary', drivers MUST NOT set the slaveOK wire protocol flag * and MUST NOT use $readPreference * * For mode 'secondary', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference * * For mode 'primaryPreferred', drivers MUST set the slaveOK wire protocol * flag and MUST also use $readPreference * * For mode 'secondaryPreferred', drivers MUST set the slaveOK wire protocol * flag. If the read preference contains a non-empty tag_sets parameter, * drivers MUST use $readPreference; otherwise, drivers MUST NOT use * $readPreference * * For mode 'nearest', drivers MUST set the slaveOK wire protocol flag and * MUST also use $readPreference */ if (mode == MONGOC_READ_SECONDARY_PREFERRED && bson_empty0 (tags)) { result->flags |= MONGOC_QUERY_SLAVE_OK; } else if (mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_QUERY_SLAVE_OK; /* Server Selection Spec: "When any $ modifier is used, including the * $readPreference modifier, the query MUST be provided using the $query * modifier". * * This applies to commands, too. */ result->query_with_read_prefs = bson_new (); result->query_owned = true; if (bson_has_field (query_bson, "$query")) { bson_concat (result->query_with_read_prefs, query_bson); } else { bson_append_document (result->query_with_read_prefs, "$query", 6, query_bson); } bson_append_document_begin (result->query_with_read_prefs, "$readPreference", 15, &child); mode_str = _get_read_mode_string (mode); bson_append_utf8 (&child, "mode", 4, mode_str, -1); if (!bson_empty0 (tags)) { bson_append_array (&child, "tags", 4, tags); } bson_append_document_end (result->query_with_read_prefs, &child); } }