Exemple #1
0
static void
test_bool (void)
{
   bson_t bcon, expected;

   bson_init (&bcon);
   bson_init (&expected);

   bson_append_bool (&expected, "foo", -1, 1);

   BCON_APPEND (&bcon, "foo", BCON_BOOL (1));

   bson_eq_bson (&bcon, &expected);

   bson_reinit (&bcon);
   bson_reinit (&expected);

   bson_append_bool (&expected, "foo", -1, 0);

   BCON_APPEND (&bcon, "foo", BCON_BOOL (0));

   bson_eq_bson (&bcon, &expected);

   bson_destroy (&bcon);
   bson_destroy (&expected);
}
Exemple #2
0
static void
test_concat (void)
{
   bson_t bcon, expected, child, child2;

   bson_init (&bcon);
   bson_init (&expected);
   bson_init (&child);
   bson_init (&child2);

   bson_append_utf8 (&child, "hello", -1, "world", -1);
   bson_append_document (&expected, "foo", -1, &child);

   BCON_APPEND (&bcon, "foo", "{", BCON(&child), "}");

   bson_eq_bson (&bcon, &expected);

   bson_reinit (&bcon);
   bson_reinit (&expected);
   bson_reinit (&child);

   bson_append_utf8 (&child, "0", -1, "bar", -1);
   bson_append_utf8 (&child, "1", -1, "baz", -1);
   bson_append_array (&expected, "foo", -1, &child);

   bson_append_utf8 (&child2, "0", -1, "baz", -1);
   BCON_APPEND (&bcon, "foo", "[", "bar", BCON(&child2), "]");

   bson_eq_bson (&bcon, &expected);

   bson_destroy (&bcon);
   bson_destroy (&child);
   bson_destroy (&child2);
   bson_destroy (&expected);
}
static bool
_mongoc_cursor_transform_next (mongoc_cursor_t *cursor,
                               const bson_t   **bson)
{
   mongoc_cursor_transform_t *transform;

   ENTRY;

   transform = cursor->iface_data;

   for (;; ) {
      if (!_mongoc_cursor_next (cursor, bson)) {
         RETURN (false);
      }

      switch (transform->filter (*bson, transform->ctx)) {
      case MONGO_CURSOR_TRANSFORM_DROP:
         break;
      case MONGO_CURSOR_TRANSFORM_PASS:
         RETURN (true);
         break;
      case MONGO_CURSOR_TRANSFORM_MUTATE:
         bson_reinit (&transform->tmp);

         transform->mutate (*bson, &transform->tmp, transform->ctx);
         *bson = &transform->tmp;
         RETURN (true);

         break;
      default:
         abort ();
         break;
      }
   }
}
Exemple #4
0
bool
mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file, bson_error_t *error)
{
   bson_t sel = BSON_INITIALIZER;
   bool ret = false;

   BSON_ASSERT (file);

   BSON_APPEND_VALUE (&sel, "_id", &file->files_id);

   if (!mongoc_collection_delete_one (
          file->gridfs->files, &sel, NULL, NULL, error)) {
      goto cleanup;
   }

   bson_reinit (&sel);
   BSON_APPEND_VALUE (&sel, "files_id", &file->files_id);

   if (!mongoc_collection_delete_many (
          file->gridfs->chunks, &sel, NULL, NULL, error)) {
      goto cleanup;
   }

   ret = true;

cleanup:
   bson_destroy (&sel);

   return ret;
}
Exemple #5
0
int
main (int argc, char *argv[])
{
   bson_json_reader_t *reader;
   bson_error_t error;
   const char *filename;
   bson_t doc = BSON_INITIALIZER;
   int i;
   int b;

   /*
    * Print program usage if no arguments are provided.
    */
   if (argc == 1) {
      fprintf (stderr, "usage: %s FILE...\n", argv[0]);
      return 1;
   }

   /*
    * Process command line arguments expecting each to be a filename.
    */
   for (i = 1; i < argc; i++) {
      filename = argv[i];

      /*
       * Open the filename provided in command line arguments.
       */
      if (0 == strcmp (filename, "-")) {
         reader = bson_json_reader_new_from_fd (STDIN_FILENO, false);
      } else {
         if (!(reader = bson_json_reader_new_from_file (filename, &error))) {
            fprintf (
               stderr, "Failed to open \"%s\": %s\n", filename, error.message);
            continue;
         }
      }

      /*
       * Convert each incoming document to BSON and print to stdout.
       */
      while ((b = bson_json_reader_read (reader, &doc, &error))) {
         if (b < 0) {
            fprintf (stderr, "Error in json parsing:\n%s\n", error.message);
            abort ();
         }

         if (fwrite (bson_get_data (&doc), 1, doc.len, stdout) != doc.len) {
            fprintf (stderr, "Failed to write to stdout, exiting.\n");
            exit (1);
         }
         bson_reinit (&doc);
      }

      bson_json_reader_destroy (reader);
      bson_destroy (&doc);
   }

   return 0;
}
Exemple #6
0
int
main (int argc, char *argv[])
{
   int i;
   int n;
   int bcon;
   bson_t bson, foo, bar, baz;
   bson_init (&bson);

   if (argc != 3) {
      fprintf (stderr,
               "usage: bcon-speed NUM_ITERATIONS [y|n]\n"
               "\n"
               "  y = perform speed tests with bcon\n"
               "  n = perform speed tests with bson_append\n"
               "\n");
      return EXIT_FAILURE;
   }

   assert (argc == 3);

   n = atoi (argv[1]);
   bcon = (argv[2][0] == 'y') ? 1 : 0;

   for (i = 0; i < n; i++) {
      if (bcon) {
         BCON_APPEND (&bson,
                      "foo",
                      "{",
                      "bar",
                      "{",
                      "baz",
                      "[",
                      BCON_INT32 (1),
                      BCON_INT32 (2),
                      BCON_INT32 (3),
                      "]",
                      "}",
                      "}");
      } else {
         bson_append_document_begin (&bson, "foo", -1, &foo);
         bson_append_document_begin (&foo, "bar", -1, &bar);
         bson_append_array_begin (&bar, "baz", -1, &baz);
         bson_append_int32 (&baz, "0", -1, 1);
         bson_append_int32 (&baz, "1", -1, 2);
         bson_append_int32 (&baz, "2", -1, 3);
         bson_append_array_end (&bar, &baz);
         bson_append_document_end (&foo, &bar);
         bson_append_document_end (&bson, &foo);
      }

      bson_reinit (&bson);
   }

   bson_destroy (&bson);

   return 0;
}
static void
test_mongoc_matcher_in_basic (void)
{
   mongoc_matcher_t *matcher;
   bson_error_t error;
   bool r;
   bson_t *spec;
   bson_t doc = BSON_INITIALIZER;

   spec = BCON_NEW ("key", "{",
                       "$in", "[",
                          BCON_INT32 (1),
                          BCON_INT32 (2),
                          BCON_INT32 (3),
                       "]",
                    "}");

   matcher = mongoc_matcher_new (spec, &error);
   r = mongoc_matcher_match (matcher, &doc);
   ASSERT (!r);

   bson_reinit (&doc);
   bson_append_int32 (&doc, "key", 3, 1);
   r = mongoc_matcher_match (matcher, &doc);
   ASSERT (r);

   bson_reinit (&doc);
   bson_append_int32 (&doc, "key", 3, 2);
   r = mongoc_matcher_match (matcher, &doc);
   ASSERT (r);

   bson_reinit (&doc);
   bson_append_int32 (&doc, "key", 3, 3);
   r = mongoc_matcher_match (matcher, &doc);
   ASSERT (r);

   bson_reinit (&doc);
   bson_append_int32 (&doc, "key", 3, 4);
   r = mongoc_matcher_match (matcher, &doc);
   ASSERT (!r);

   bson_destroy (&doc);
   bson_destroy (spec);
   mongoc_matcher_destroy (matcher);
}
static void
test_command (void)
{
   mongoc_database_t *database;
   mongoc_client_t *client;
   mongoc_cursor_t *cursor;
   bson_error_t error;
   const bson_t *doc;
   bool r;
   bson_t cmd = BSON_INITIALIZER;
   bson_t reply;

   client = mongoc_client_new (gTestUri);
   assert (client);

   database = mongoc_client_get_database (client, "admin");

   /*
    * Test a known working command, "ping".
    */
   bson_append_int32 (&cmd, "ping", 4, 1);

   cursor = mongoc_database_command (database, MONGOC_QUERY_NONE, 0, 1, 0, &cmd, NULL, NULL);
   assert (cursor);

   r = mongoc_cursor_next (cursor, &doc);
   assert (r);
   assert (doc);

   r = mongoc_cursor_next (cursor, &doc);
   assert (!r);
   assert (!doc);

   mongoc_cursor_destroy (cursor);


   /*
    * Test a non-existing command to ensure we get the failure.
    */
   bson_reinit (&cmd);
   bson_append_int32 (&cmd, "a_non_existing_command", -1, 1);

   r = mongoc_database_command_simple (database, &cmd, NULL, &reply, &error);
   assert (!r);
   assert (error.domain == MONGOC_ERROR_QUERY);
   assert (error.code == MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND);
   assert (!strcmp ("no such cmd: a_non_existing_command", error.message));

   mongoc_database_destroy (database);
   mongoc_client_destroy (client);
   bson_destroy (&cmd);
}
Exemple #9
0
    void reinit() {
        while (!_stack.empty()) {
            _stack.pop_back();
        }

        bson_reinit(&_root);

        _depth = 0;

        _n = 0;

        _has_user_key = false;
    }
static void
test_validate (void)
{
   mongoc_collection_t *collection;
   mongoc_client_t *client;
   bson_iter_t iter;
   bson_error_t error;
   bson_t doc = BSON_INITIALIZER;
   bson_t opts = BSON_INITIALIZER;
   bson_t reply;
   bool r;

   client = mongoc_client_new (gTestUri);
   ASSERT (client);

   collection = get_test_collection (client, "test_validate");
   ASSERT (collection);

   r = mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &doc, NULL, &error);
   assert (r);

   BSON_APPEND_BOOL (&opts, "full", true);

   r = mongoc_collection_validate (collection, &opts, &reply, &error);
   assert (r);

   assert (bson_iter_init_find (&iter, &reply, "ns"));
   assert (bson_iter_init_find (&iter, &reply, "valid"));

   bson_destroy (&reply);

   bson_reinit (&opts);
   BSON_APPEND_UTF8 (&opts, "full", "bad_value");

   r = mongoc_collection_validate (collection, &opts, &reply, &error);
   assert (!r);
   assert (error.domain == MONGOC_ERROR_BSON);
   assert (error.code == MONGOC_ERROR_BSON_INVALID);

   r = mongoc_collection_drop (collection, &error);
   assert (r);

   mongoc_collection_destroy (collection);
   mongoc_client_destroy (client);
   bson_destroy (&doc);
   bson_destroy (&opts);
}
Exemple #11
0
/**
 * mongoc_read_concern_freeze:
 * @read_concern: A mongoc_read_concern_t.
 *
 * This is an internal function.
 *
 * Encodes the read concern into a bson_t, which may then be returned by
 * mongoc_read_concern_get_bson().
 */
static void
_mongoc_read_concern_freeze (mongoc_read_concern_t *read_concern)
{
   bson_t *compiled;

   BSON_ASSERT (read_concern);

   compiled = &read_concern->compiled;

   read_concern->frozen = true;

   bson_reinit (compiled);

   if (read_concern->level) {
      BSON_APPEND_UTF8 (compiled, "level", read_concern->level);
   }
}
Exemple #12
0
static void
_test_bson_json_read_compare (const char *json,
                              int         size,
                              ...)
{
   bson_error_t error = { 0 };
   bson_json_reader_t *reader;
   va_list ap;
   int r;
   bson_t *compare;
   bson_t bson = BSON_INITIALIZER;

   reader = bson_json_data_reader_new ((size == 1), size);
   bson_json_data_reader_ingest(reader, (uint8_t *)json, strlen(json));

   va_start (ap, size);

   while ((r = bson_json_reader_read (reader, &bson, &error))) {
      if (r == -1) {
         fprintf (stderr, "%s\n", error.message);
         abort ();
      }

      compare = va_arg (ap, bson_t *);

      assert (compare);

      bson_eq_bson (&bson, compare);

      bson_destroy (compare);

      bson_reinit (&bson);
   }

   va_end (ap);

   bson_json_reader_destroy (reader);
   bson_destroy (&bson);
}
bool
mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file,
                           bson_error_t         *error)
{
   bson_t sel = BSON_INITIALIZER;
   bool ret = false;

   bson_return_val_if_fail (file, false);

   BSON_APPEND_VALUE (&sel, "_id", &file->files_id);

   if (!mongoc_collection_remove (file->gridfs->files,
                                  MONGOC_REMOVE_SINGLE_REMOVE,
                                  &sel,
                                  NULL,
                                  error)) {
      goto cleanup;
   }

   bson_reinit (&sel);
   BSON_APPEND_VALUE (&sel, "files_id", &file->files_id);

   if (!mongoc_collection_remove (file->gridfs->chunks,
                                  MONGOC_REMOVE_NONE,
                                  &sel,
                                  NULL,
                                  error)) {
      goto cleanup;
   }

   ret = true;

cleanup:
   bson_destroy (&sel);

   return ret;
}
static void
test_func_inherits_opts (void *ctx)
{
   opt_inheritance_test_t *test = (opt_inheritance_test_t *) ctx;

   /* for example, test mongoc_collection_find_with_opts with no read pref,
    * with a read pref set on the collection (OPT_SOURCE_COLL), with an explicit
    * read pref (OPT_SOURCE_FUNC), or with one read pref on the collection and
    * a different one passed explicitly */
   opt_source_t source_matrix[] = {OPT_SOURCE_NONE,
                                   test->opt_source,
                                   OPT_SOURCE_FUNC,
                                   test->opt_source | OPT_SOURCE_FUNC};

   size_t i;
   func_ctx_t func_ctx;
   mock_rs_t *rs;
   mongoc_client_t *client;
   mongoc_database_t *db;
   mongoc_collection_t *collection;
   bson_t opts = BSON_INITIALIZER;
   mongoc_read_prefs_t *func_prefs = NULL;
   future_t *future;
   request_t *request;
   bson_t cmd = BSON_INITIALIZER;
   bool expect_secondary;
   bson_error_t error;

   /* one primary, one secondary */
   rs = mock_rs_with_autoismaster (WIRE_VERSION_OP_MSG, true, 1, 0);
   /* we use read pref tags like "collection": "yes" to verify where the
    * pref was inherited from; ensure all secondaries match all tags */
   mock_rs_tag_secondary (rs,
                          0,
                          tmp_bson ("{'client': 'yes',"
                                    " 'database': 'yes',"
                                    " 'collection': 'yes',"
                                    " 'function': 'yes'}"));

   mock_rs_run (rs);

   /* iterate over all combinations of options sources: e.g., an option set on
    * collection and not function, on function not collection, both, neither */
   for (i = 0; i < sizeof (source_matrix) / (sizeof (opt_source_t)); i++) {
      expect_secondary = false;
      func_prefs = NULL;
      bson_reinit (&cmd);
      bson_reinit (&opts);

      client = mongoc_client_new_from_uri (mock_rs_get_uri (rs));
      if (source_matrix[i] & OPT_SOURCE_CLIENT) {
         set_client_opt (client, test->opt_type);
      }

      db = mongoc_client_get_database (client, "database");
      if (source_matrix[i] & OPT_SOURCE_DB) {
         set_database_opt (db, test->opt_type);
      }

      collection = mongoc_database_get_collection (db, "collection");
      if (source_matrix[i] & OPT_SOURCE_COLL) {
         set_collection_opt (collection, test->opt_type);
      }

      if (source_matrix[i] & OPT_SOURCE_FUNC) {
         set_func_opt (&opts, &func_prefs, test->opt_type);
      }

      func_ctx_init (
         &func_ctx, test, client, db, collection, func_prefs, &opts);

      /* func_with_opts creates expected "cmd", like {insert: 'collection'} */
      future = test->func_with_opts (&func_ctx, &cmd);

      if (source_matrix[i] != OPT_SOURCE_NONE) {
         add_expected_opt (source_matrix[i], test->opt_type, &cmd);
         if (test->opt_type == OPT_READ_PREFS) {
            expect_secondary = true;
         }
      }

      /* write commands send two OP_MSG sections */
      if (test->n_sections == 2) {
         request = mock_rs_receives_msg (rs, 0, &cmd, tmp_bson ("{}"));
      } else {
         request = mock_rs_receives_msg (rs, 0, &cmd);
      }

      if (expect_secondary) {
         BSON_ASSERT (mock_rs_request_is_to_secondary (rs, request));
      } else {
         BSON_ASSERT (mock_rs_request_is_to_primary (rs, request));
      }

      if (func_ctx.cursor) {
         mock_server_replies_simple (request,
                                     "{'ok': 1,"
                                     " 'cursor': {"
                                     "    'id': 0,"
                                     "    'ns': 'db.collection',"
                                     "    'firstBatch': []}}");

         BSON_ASSERT (!future_get_bool (future));
         future_destroy (future);
         ASSERT_OR_PRINT (!mongoc_cursor_error (func_ctx.cursor, &error),
                          error);
      } else {
         mock_server_replies_simple (request, "{'ok': 1}");
         cleanup_future (future);
      }

      request_destroy (request);
      mongoc_read_prefs_destroy (func_prefs);
      func_ctx_cleanup (&func_ctx);
      mongoc_collection_destroy (collection);
      mongoc_database_destroy (db);
      mongoc_client_destroy (client);
   }

   bson_destroy (&cmd);
   bson_destroy (&opts);
   mock_rs_destroy (rs);
}
static bool
txn_commit (mongoc_client_session_t *session,
            bool explicitly_retrying,
            bson_t *reply,
            bson_error_t *error)
{
   bson_t cmd = BSON_INITIALIZER;
   bson_t opts = BSON_INITIALIZER;
   bson_error_t err_local;
   bson_error_t *err_ptr = error ? error : &err_local;
   bson_t reply_local = BSON_INITIALIZER;
   mongoc_write_err_type_t error_type;
   bool r = false;
   bool retrying_after_error = false;
   mongoc_write_concern_t *retry_wc = NULL;

   _mongoc_bson_init_if_set (reply);

   BSON_APPEND_INT32 (&cmd, "commitTransaction", 1);

retry:
   if (!mongoc_client_session_append (session, &opts, err_ptr)) {
      GOTO (done);
   }

   /* Transactions Spec: "When commitTransaction is retried, either by the
    * driver's internal retry-once logic or explicitly by the user calling
    * commitTransaction again, drivers MUST apply w:majority to the write
    * concern of the commitTransaction command." */
   if (!retry_wc && (retrying_after_error || explicitly_retrying)) {
      retry_wc = create_commit_retry_wc (session->txn.opts.write_concern
                                            ? session->txn.opts.write_concern
                                            : session->client->write_concern);
   }

   if (retry_wc || session->txn.opts.write_concern) {
      if (!mongoc_write_concern_append (
             retry_wc ? retry_wc : session->txn.opts.write_concern, &opts)) {
         bson_set_error (err_ptr,
                         MONGOC_ERROR_TRANSACTION,
                         MONGOC_ERROR_TRANSACTION_INVALID_STATE,
                         "Invalid transaction write concern");
         GOTO (done);
      }
   }

   /* will be reinitialized by mongoc_client_write_command_with_opts */
   bson_destroy (&reply_local);
   r = mongoc_client_write_command_with_opts (
      session->client, "admin", &cmd, &opts, &reply_local, err_ptr);

   /* Transactions Spec: "Drivers MUST retry the commitTransaction command once
    * after it fails with a retryable error", same for abort */
   error_type = _mongoc_write_error_get_type (r, err_ptr, &reply_local);
   if (!retrying_after_error && error_type == MONGOC_WRITE_ERR_RETRY) {
      retrying_after_error = true; /* retry after error only once */
      bson_reinit (&opts);
      GOTO (retry);
   }

   /* Transactions Spec: "add the UnknownTransactionCommitResult error label
    * when commitTransaction fails with a network error, server selection
    * error, or write concern failed / timeout." */
   if (reply) {
      if ((!r && err_ptr->domain == MONGOC_ERROR_SERVER_SELECTION) ||
          error_type == MONGOC_WRITE_ERR_RETRY ||
          error_type == MONGOC_WRITE_ERR_WRITE_CONCERN) {
         bson_copy_to_excluding_noinit (
            &reply_local, reply, "errorLabels", NULL);
         copy_labels_plus_unknown_commit_result (&reply_local, reply);
      } else {
         /* maintain invariants: reply & reply_local are valid until the end */
         bson_destroy (reply);
         bson_steal (reply, &reply_local);
         bson_init (&reply_local);
      }
   }

done:
   bson_destroy (&reply_local);
   bson_destroy (&cmd);
   bson_destroy (&opts);

   if (retry_wc) {
      mongoc_write_concern_destroy (retry_wc);
   }

   return r;
}
Exemple #16
0
static void
_mongoc_write_opquery (mongoc_write_command_t *command,
                       mongoc_client_t *client,
                       mongoc_server_stream_t *server_stream,
                       const char *database,
                       const char *collection,
                       const mongoc_write_concern_t *write_concern,
                       uint32_t offset,
                       mongoc_write_result_t *result,
                       bson_error_t *error)
{
   mongoc_cmd_parts_t parts;
   bson_iter_t iter;
   const char *key;
   uint32_t len = 0;
   bson_t ar;
   bson_t cmd;
   bson_t reply;
   char str[16];
   bool has_more;
   bool ret = false;
   uint32_t i;
   int32_t max_bson_obj_size;
   int32_t max_write_batch_size;
   uint32_t overhead;
   uint32_t key_len;
   int data_offset = 0;
   bson_reader_t *reader;
   const bson_t *bson;
   bool eof;

   ENTRY;

   BSON_ASSERT (command);
   BSON_ASSERT (client);
   BSON_ASSERT (database);
   BSON_ASSERT (server_stream);
   BSON_ASSERT (collection);

   bson_init (&cmd);
   max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream);
   max_write_batch_size =
      mongoc_server_stream_max_write_batch_size (server_stream);

again:
   has_more = false;
   i = 0;

   _mongoc_write_command_init (&cmd, command, collection);

   /* 1 byte to specify array type, 1 byte for field name's null terminator */
   overhead = cmd.len + 2 + gCommandFieldLens[command->type];


   reader = bson_reader_new_from_data (command->payload.data + data_offset,
                                       command->payload.len - data_offset);

   bson_append_array_begin (&cmd,
                            gCommandFields[command->type],
                            gCommandFieldLens[command->type],
                            &ar);

   while ((bson = bson_reader_read (reader, &eof))) {
      key_len = (uint32_t) bson_uint32_to_string (i, &key, str, sizeof str);
      len = bson->len;
      /* 1 byte to specify document type, 1 byte for key's null terminator */
      if (_mongoc_write_command_will_overflow (overhead,
                                               key_len + len + 2 + ar.len,
                                               i,
                                               max_bson_obj_size,
                                               max_write_batch_size)) {
         has_more = true;
         break;
      }
      BSON_APPEND_DOCUMENT (&ar, key, bson);
      data_offset += len;
      i++;
   }

   bson_append_array_end (&cmd, &ar);

   if (!i) {
      _mongoc_write_command_too_large_error (error, i, len, max_bson_obj_size);
      result->failed = true;
      result->must_stop = true;
      ret = false;
      if (bson) {
         data_offset += len;
      }
   } else {
      mongoc_cmd_parts_init (&parts, client, database, MONGOC_QUERY_NONE, &cmd);
      parts.is_write_command = true;
      parts.assembled.operation_id = command->operation_id;
      if (!mongoc_cmd_parts_set_write_concern (
             &parts,
             write_concern,
             server_stream->sd->max_wire_version,
             error)) {
         bson_reader_destroy (reader);
         bson_destroy (&cmd);
         mongoc_cmd_parts_cleanup (&parts);
         EXIT;
      }

      BSON_ASSERT (bson_iter_init (&iter, &command->cmd_opts));
      if (!mongoc_cmd_parts_append_opts (
             &parts, &iter, server_stream->sd->max_wire_version, error)) {
         bson_reader_destroy (reader);
         bson_destroy (&cmd);
         mongoc_cmd_parts_cleanup (&parts);
         EXIT;
      }

      ret = mongoc_cmd_parts_assemble (&parts, server_stream, error);
      if (ret) {
         ret = mongoc_cluster_run_command_monitored (
            &client->cluster, &parts.assembled, &reply, error);
      } else {
         /* assembling failed */
         result->must_stop = true;
         bson_init (&reply);
      }

      if (!ret) {
         result->failed = true;
         if (bson_empty (&reply)) {
            /* assembling failed, or a network error running the command */
            result->must_stop = true;
         }
      }

      _mongoc_write_result_merge (result, command, &reply, offset);
      offset += i;
      bson_destroy (&reply);
      mongoc_cmd_parts_cleanup (&parts);
   }
   bson_reader_destroy (reader);

   if (has_more && (ret || !command->flags.ordered) && !result->must_stop) {
      bson_reinit (&cmd);
      GOTO (again);
   }

   bson_destroy (&cmd);
   EXIT;
}
int64_t
load_table (mongoc_database_t *db,
            const char        *table_name,
            bson_t            *bson_schema)
{
    int64_t ret = true;
    column_map_t *column_map, *column_map_p;
    int column_map_size, i;
    double start_time, end_time, delta_time;
    FILE *fp;
    mongoc_collection_t *collection;
    mongoc_bulk_operation_t *bulk;
    size_t n_docs = 0;
    char *token;
    bson_t bson, reply;
    int64_t count = 0;
    bson_error_t error;

    fprintf (stderr, "load_table table_name: \"%s\"\n", table_name);
    get_column_map (bson_schema, table_name, &column_map, &column_map_size) || DIE;
    snprintf (mbdump_file, MAXPATHLEN, "%s/%s", mbdump_dir, table_name);
    /* fprintf (stderr, "mbdump_file: \"%s\"\n", mbdump_file); */
    start_time = dtimeofday ();
    fp = fopen (mbdump_file, "r");
    if (!fp) DIE;
    collection = mongoc_database_get_collection (db, table_name);
    bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
    bson_init (&bson);
    while (ret && fgets (buf, BUFSIZ, fp)) {
        /*
        fputs (buf, stdout);
        */
        chomp (buf);
        for (i = 0, column_map_p = column_map, token = strtok_single (buf, "\t");
             i < column_map_size;
             i++, column_map_p++, token = strtok_single (NULL, "\t")) {
             bool ret;
             /*
             fprintf (stderr, "%s: \"%s\" [%d/%d](%s)\n", column_map_p->column_name, token, i, column_map_size, column_map_p->data_type);
             fflush (stdout);
             */
             ret = (*column_map_p->bson_append_from_s) (&bson, column_map_p->column_name, token);
             ret || fprintf (stderr, "WARNING: column_map_p->bson_append_from_s failed column %s: \"%s\" [%d/%d](%s)\n",
                            column_map_p->column_name, token, i, column_map_size, column_map_p->data_type);
        }
        /*
        bson_printf ("bson: %s\n", &bson);
        */
        mongoc_bulk_operation_insert (bulk, &bson);
        bson_reinit (&bson);
        if (++n_docs == BULK_OPS_SIZE) {
           ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
           if (ret) {
              count += n_docs;
              if (count % PROGRESS_SIZE == 0) {
                  fputc('.', stdout);
                  fflush(stdout);
              }
           }
           else
              fprintf (stderr, "mongoc_cursor_bulk_insert execute failure: %s\n", error.message);
           n_docs = 0;
           mongoc_bulk_operation_destroy (bulk);
           bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
        }
    }
    if (ret && n_docs > 0) {
       ret = mongoc_bulk_operation_execute (bulk, &reply, &error);
       if (ret)
          count += n_docs;
       else
          fprintf (stderr, "mongoc_cursor_bulk_insert execute failure: %s\n", error.message);
    }
    fputc('.', stdout);
    fputc('\n', stdout);
    fflush(stdout);
    bson_destroy (&bson);
    mongoc_bulk_operation_destroy (bulk);
    mongoc_collection_destroy (collection);
    fclose (fp);
    end_time = dtimeofday ();
    delta_time = end_time - start_time + 0.0000001;
    fprintf (stderr, "info: real: %.2f, count: %"PRId64", %"PRId64" docs/sec\n", delta_time, count, (int64_t)round (count/delta_time));
    fflush (stderr);
    free (column_map);
    return ret ? count : -1;
}
bool
mongoc_change_stream_next (mongoc_change_stream_t *stream, const bson_t **bson)
{
   bson_iter_t iter;
   bool ret = false;

   BSON_ASSERT (stream);
   BSON_ASSERT (bson);

   if (stream->err.code != 0) {
      goto end;
   }

   BSON_ASSERT (stream->cursor);
   if (!mongoc_cursor_next (stream->cursor, bson)) {
      const bson_t *err_doc;
      bson_error_t err;
      bool resumable = false;

      if (!mongoc_cursor_error_document (stream->cursor, &err, &err_doc)) {
         /* no error occurred, just no documents left. */
         goto end;
      }

      resumable = _is_resumable_error (err_doc);
      if (resumable) {
         /* recreate the cursor. */
         mongoc_cursor_destroy (stream->cursor);
         stream->cursor = NULL;
         if (!_make_cursor (stream)) {
            goto end;
         }
         if (!mongoc_cursor_next (stream->cursor, bson)) {
            resumable =
               !mongoc_cursor_error_document (stream->cursor, &err, &err_doc);
            if (resumable) {
               /* empty batch. */
               goto end;
            }
         }
      }

      if (!resumable) {
         stream->err = err;
         bson_destroy (&stream->err_doc);
         bson_copy_to (err_doc, &stream->err_doc);
         goto end;
      }
   }

   /* we have received documents, either from the first call to next or after a
    * resume. */
   if (!bson_iter_init_find (&iter, *bson, "_id")) {
      bson_set_error (&stream->err,
                      MONGOC_ERROR_CURSOR,
                      MONGOC_ERROR_CHANGE_STREAM_NO_RESUME_TOKEN,
                      "Cannot provide resume functionality when the resume "
                      "token is missing");
      goto end;
   }

   /* copy the resume token. */
   bson_reinit (&stream->resume_token);
   BSON_APPEND_VALUE (
      &stream->resume_token, "resumeAfter", bson_iter_value (&iter));
   /* clear out the operation time, since we no longer need it to resume. */
   _mongoc_timestamp_clear (&stream->operation_time);
   ret = true;

end:
   /* Driver Sessions Spec: "When an implicit session is associated with a
    * cursor for use with getMore operations, the session MUST be returned to
    * the pool immediately following a getMore operation that indicates that the
    * cursor has been exhausted." */
   if (stream->implicit_session) {
      /* if creating the change stream cursor errored, it may be null. */
      if (!stream->cursor || stream->cursor->cursor_id == 0) {
         mongoc_client_session_destroy (stream->implicit_session);
         stream->implicit_session = NULL;
      }
   }
   return ret;
}