Example #1
0
static bool
get_upserted_id (const bson_t *update, bson_value_t *upserted_id)
{
   bson_iter_t iter;
   bson_iter_t id_iter;

   /* Versions of MongoDB before 2.6 don't return the _id for an upsert if _id
    * is not an ObjectId, so find it in the update document's query "q" or
    * update "u". It must be in one or both: if it were in neither the _id
    * would be server-generated, therefore an ObjectId, therefore returned and
    * we wouldn't call this function. If _id is in both the update document
    * *and* the query spec the update document _id takes precedence.
    */

   bson_iter_init (&iter, update);

   if (bson_iter_find_descendant (&iter, "u._id", &id_iter)) {
      bson_value_copy (bson_iter_value (&id_iter), upserted_id);
      return true;
   } else {
      bson_iter_init (&iter, update);

      if (bson_iter_find_descendant (&iter, "q._id", &id_iter)) {
         bson_value_copy (bson_iter_value (&id_iter), upserted_id);
         return true;
      }
   }

   /* server bug? */
   return false;
}
bool
_mongoc_convert_bson_value_t (mongoc_client_t *client,
                              const bson_iter_t *iter,
                              bson_value_t *value,
                              bson_error_t *error)
{
   bson_value_copy (bson_iter_value ((bson_iter_t *) iter), value);
   return true;
}
Example #3
0
bson_value_t* _aggregate_get_value_at_key(bson_t *doc, char *key) {
        bson_iter_t iter;
        bson_iter_t child_iter;
        if (!bson_iter_init (&iter, doc) ||
            !bson_iter_find_descendant (&iter, key, &child_iter)) {
            return NULL;
        }

        bson_value_t *result = bson_malloc(sizeof(bson_value_t));
        bson_value_copy(bson_iter_value(&child_iter), result);
        return result;
}
Example #4
0
bool
mongoc_gridfs_file_set_id (mongoc_gridfs_file_t *file,
                           const bson_value_t *id,
                           bson_error_t *error)
{
   if (!file->is_dirty) {
      bson_set_error (error,
                      MONGOC_ERROR_GRIDFS,
                      MONGOC_ERROR_GRIDFS_PROTOCOL_ERROR,
                      "Cannot set file id after saving file.");
      return false;
   }
   bson_value_copy (id, &file->files_id);
   return true;
}
Example #5
0
static void
test_value_decimal128 (void)
{
   const bson_value_t *value;
   bson_value_t copy;
   bson_iter_t iter;
   bson_decimal128_t dec;
   bson_t other = BSON_INITIALIZER;
   bson_t *doc;

   assert (bson_decimal128_from_string ("123.5", &dec));
   doc = BCON_NEW ("decimal128", BCON_DECIMAL128 (&dec));
   assert (bson_iter_init (&iter, doc) && bson_iter_next (&iter));
   assert (value = bson_iter_value (&iter));
   bson_value_copy (value, &copy);
   assert (bson_append_value (&other, bson_iter_key (&iter), -1, &copy));

   bson_value_destroy (&copy);
   bson_destroy (doc);
   bson_destroy (&other);
}
Example #6
0
static void
test_value_basic (void)
{
   static const uint8_t raw[16] = { 0 };
   const bson_value_t *value;
   bson_value_t copy;
   bson_iter_t iter;
   bson_oid_t oid;
   bson_t other = BSON_INITIALIZER;
   bson_t *doc;
   bson_t sub = BSON_INITIALIZER;
   bool r;
   int i;

   bson_oid_init (&oid, NULL);

   doc = BCON_NEW ("double", BCON_DOUBLE (123.4),
                   "utf8", "this is my string",
                   "document", BCON_DOCUMENT (&sub),
                   "array", BCON_DOCUMENT (&sub),
                   "binary", BCON_BIN (BSON_SUBTYPE_BINARY, raw, sizeof raw),
                   "undefined", BCON_UNDEFINED,
                   "oid", BCON_OID (&oid),
                   "bool", BCON_BOOL (true),
                   "datetime", BCON_DATE_TIME (12345678),
                   "null", BCON_NULL,
                   "regex", BCON_REGEX ("^hello", "i"),
                   "dbpointer", BCON_DBPOINTER ("test.test", &oid),
                   "code", BCON_CODE ("var a = function() {}"),
                   "symbol", BCON_SYMBOL ("my_symbol"),
                   "codewscope", BCON_CODEWSCOPE ("var a = 1;", &sub),
                   "int32", BCON_INT32 (1234),
                   "timestamp", BCON_TIMESTAMP (1234, 4567),
                   "int64", BCON_INT32 (4321),
                   "maxkey", BCON_MAXKEY,
                   "minkey", BCON_MINKEY);

   r = bson_iter_init (&iter, doc);
   assert (r);

   for (i = 0; i < 20; i++) {
      r = bson_iter_next (&iter);
      assert (r);

      value = bson_iter_value (&iter);
      assert (value);

      bson_value_copy (value, &copy);

      r = bson_append_value (&other, bson_iter_key (&iter), -1, &copy);
      assert (r);

      bson_value_destroy (&copy);
   }

   r = bson_iter_next (&iter);
   assert (!r);

   bson_destroy (doc);
   bson_destroy (&other);
}
/**
 * _mongoc_gridfs_file_new_from_bson:
 *
 * creates a gridfs file from a bson object
 *
 * This is only really useful for instantiating a gridfs file from a server
 * side object
 */
mongoc_gridfs_file_t *
_mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs,
                                   const bson_t    *data)
{
   mongoc_gridfs_file_t *file;
   const bson_value_t *value;
   const char *key;
   bson_iter_t iter;
   const uint8_t *buf;
   uint32_t buf_len;

   ENTRY;

   BSON_ASSERT (gridfs);
   BSON_ASSERT (data);

   file = (mongoc_gridfs_file_t *)bson_malloc0 (sizeof *file);

   file->gridfs = gridfs;
   bson_copy_to (data, &file->bson);

   bson_iter_init (&iter, &file->bson);

   while (bson_iter_next (&iter)) {
      key = bson_iter_key (&iter);

      if (0 == strcmp (key, "_id")) {
         value = bson_iter_value (&iter);
         bson_value_copy (value, &file->files_id);
      } else if (0 == strcmp (key, "length")) {
         if (!BSON_ITER_HOLDS_INT32 (&iter) &&
             !BSON_ITER_HOLDS_INT64 (&iter) &&
             !BSON_ITER_HOLDS_DOUBLE (&iter)) {
            GOTO (failure);
         }
         file->length = bson_iter_as_int64 (&iter);
      } else if (0 == strcmp (key, "chunkSize")) {
         if (!BSON_ITER_HOLDS_INT32 (&iter) &&
             !BSON_ITER_HOLDS_INT64 (&iter) &&
             !BSON_ITER_HOLDS_DOUBLE (&iter)) {
            GOTO (failure);
         }
         if (bson_iter_as_int64 (&iter) > INT32_MAX) {
            GOTO (failure);
         }
         file->chunk_size = (int32_t)bson_iter_as_int64 (&iter);
      } else if (0 == strcmp (key, "uploadDate")) {
         if (!BSON_ITER_HOLDS_DATE_TIME (&iter)){
            GOTO (failure);
         }
         file->upload_date = bson_iter_date_time (&iter);
      } else if (0 == strcmp (key, "md5")) {
         if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
            GOTO (failure);
         }
         file->bson_md5 = bson_iter_utf8 (&iter, NULL);
      } else if (0 == strcmp (key, "filename")) {
         if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
            GOTO (failure);
         }
         file->bson_filename = bson_iter_utf8 (&iter, NULL);
      } else if (0 == strcmp (key, "contentType")) {
         if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
            GOTO (failure);
         }
         file->bson_content_type = bson_iter_utf8 (&iter, NULL);
      } else if (0 == strcmp (key, "aliases")) {
         if (!BSON_ITER_HOLDS_ARRAY (&iter)) {
            GOTO  (failure);
         }
         bson_iter_array (&iter, &buf_len, &buf);
         bson_init_static (&file->bson_aliases, buf, buf_len);
      } else if (0 == strcmp (key, "metadata")) {
         if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) {
            GOTO (failure);
         }
         bson_iter_document (&iter, &buf_len, &buf);
         bson_init_static (&file->bson_metadata, buf, buf_len);
      }
   }

   /* TODO: is there are a minimal object we should be verifying that we
    * actually have here? */

   RETURN (file);

failure:
   bson_destroy (&file->bson);

   RETURN (NULL);
}
Example #8
0
/* fire command-succeeded event as if we'd used a modern write command.
 * note, cluster.request_id was incremented once for the write, again
 * for the getLastError, so cluster.request_id is no longer valid; used the
 * passed-in request_id instead.
 */
static void
_mongoc_monitor_legacy_write_succeeded (mongoc_client_t *client,
                                        int64_t duration,
                                        mongoc_write_command_t *command,
                                        const bson_t *gle,
                                        mongoc_server_stream_t *stream,
                                        int64_t request_id)
{
   bson_iter_t iter;
   bson_t doc;
   int64_t ok = 1;
   int64_t n = 0;
   uint32_t code = 8;
   bool wtimeout = false;

   /* server error message */
   const char *errmsg = NULL;
   size_t errmsg_len = 0;

   /* server errInfo subdocument */
   bool has_errinfo = false;
   uint32_t len;
   const uint8_t *data;
   bson_t errinfo;

   /* server upsertedId value */
   bool has_upserted_id = false;
   bson_value_t upserted_id;

   /* server updatedExisting value */
   bool has_updated_existing = false;
   bool updated_existing = false;

   mongoc_apm_command_succeeded_t event;

   ENTRY;

   if (!client->apm_callbacks.succeeded) {
      EXIT;
   }

   /* first extract interesting fields from getlasterror response */
   if (gle) {
      bson_iter_init (&iter, gle);
      while (bson_iter_next (&iter)) {
         if (!strcmp (bson_iter_key (&iter), "ok")) {
            ok = bson_iter_as_int64 (&iter);
         } else if (!strcmp (bson_iter_key (&iter), "n")) {
            n = bson_iter_as_int64 (&iter);
         } else if (!strcmp (bson_iter_key (&iter), "code")) {
            code = (uint32_t) bson_iter_as_int64 (&iter);
            if (code == 0) {
               /* server sent non-numeric error code? */
               code = 8;
            }
         } else if (!strcmp (bson_iter_key (&iter), "upserted")) {
            has_upserted_id = true;
            bson_value_copy (bson_iter_value (&iter), &upserted_id);
         } else if (!strcmp (bson_iter_key (&iter), "updatedExisting")) {
            has_updated_existing = true;
            updated_existing = bson_iter_as_bool (&iter);
         } else if ((!strcmp (bson_iter_key (&iter), "err") ||
                     !strcmp (bson_iter_key (&iter), "errmsg")) &&
                    BSON_ITER_HOLDS_UTF8 (&iter)) {
            errmsg = bson_iter_utf8_unsafe (&iter, &errmsg_len);
         } else if (!strcmp (bson_iter_key (&iter), "errInfo") &&
                    BSON_ITER_HOLDS_DOCUMENT (&iter)) {
            bson_iter_document (&iter, &len, &data);
            bson_init_static (&errinfo, data, len);
            has_errinfo = true;
         } else if (!strcmp (bson_iter_key (&iter), "wtimeout")) {
            wtimeout = true;
         }
      }
   }

   /* based on PyMongo's _convert_write_result() */
   bson_init (&doc);
   bson_append_int32 (&doc, "ok", 2, (int32_t) ok);

   if (errmsg && !wtimeout) {
      /* Failure, but pass to the success callback. Command Monitoring Spec:
       * "Commands that executed on the server and return a status of {ok: 1}
       * are considered successful commands and fire CommandSucceededEvent.
       * Commands that have write errors are included since the actual command
       * did succeed, only writes failed." */
      append_write_err (
         &doc, code, errmsg, errmsg_len, has_errinfo ? &errinfo : NULL);
   } else {
      /* Success, perhaps with a writeConcernError. */
      if (errmsg) {
         append_write_concern_err (&doc, errmsg, errmsg_len);
      }

      if (command->type == MONGOC_WRITE_COMMAND_INSERT) {
         /* GLE result for insert is always 0 in most MongoDB versions. */
         n = command->n_documents;
      } else if (command->type == MONGOC_WRITE_COMMAND_UPDATE) {
         if (has_upserted_id) {
            append_upserted (&doc, &upserted_id);
         } else if (has_updated_existing && !updated_existing && n == 1) {
            bson_t tmp;
            int32_t bson_len = 0;

            memcpy (&bson_len, command->payload.data, 4);
            bson_len = BSON_UINT32_FROM_LE (bson_len);
            bson_init_static (&tmp, command->payload.data, bson_len);
            has_upserted_id = get_upserted_id (&tmp, &upserted_id);

            if (has_upserted_id) {
               append_upserted (&doc, &upserted_id);
            }
         }
      }
   }

   bson_append_int32 (&doc, "n", 1, (int32_t) n);

   mongoc_apm_command_succeeded_init (
      &event,
      duration,
      &doc,
      _mongoc_command_type_to_name (command->type),
      request_id,
      command->operation_id,
      &stream->sd->host,
      stream->sd->id,
      client->apm_context);

   client->apm_callbacks.succeeded (&event);

   mongoc_apm_command_succeeded_cleanup (&event);
   bson_destroy (&doc);

   if (has_upserted_id) {
      bson_value_destroy (&upserted_id);
   }

   EXIT;
}