bson_bool_t
_mongoc_cursor_next (mongoc_cursor_t  *cursor,
                     const bson_t    **bson)
{
   const bson_t *b;
   bson_bool_t eof;

   ENTRY;

   BSON_ASSERT(cursor);


   if (cursor->client->in_exhaust && ! cursor->in_exhaust) {
      bson_set_error(&cursor->error,
                     MONGOC_ERROR_CLIENT,
                     MONGOC_ERROR_CLIENT_IN_EXHAUST,
                     "Another cursor derived from this client is in exhaust.");
      cursor->failed = TRUE;
      RETURN(FALSE);
   }

   if (bson) {
      *bson = NULL;
   }

   if (cursor->limit && cursor->count >= cursor->limit) {
      return FALSE;
   }

   /*
    * Short circuit if we are finished already.
    */
   if (BSON_UNLIKELY(cursor->done)) {
      RETURN(FALSE);
   }

   /*
    * Check to see if we need to send a GET_MORE for more results.
    */
   if (!cursor->sent) {
      if (!_mongoc_cursor_query(cursor)) {
         RETURN(FALSE);
      }
   } else if (BSON_UNLIKELY(cursor->end_of_event)) {
      if (!_mongoc_cursor_get_more(cursor)) {
         RETURN(FALSE);
      }
   }

   /*
    * Read the next BSON document from the event.
    */
   eof = FALSE;
   b = bson_reader_read(cursor->reader, &eof);
   cursor->end_of_event = eof;

   cursor->done = cursor->end_of_event && (
      (cursor->in_exhaust && !cursor->rpc.reply.cursor_id) ||
      (!b && !(cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR))
      );

   /*
    * Do a supplimental check to see if we had a corrupted reply in the
    * document stream.
    */
   if (!b && !eof) {
      cursor->failed = TRUE;
      bson_set_error(&cursor->error,
                     MONGOC_ERROR_CURSOR,
                     MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                     "The reply was corrupt.");
      RETURN(FALSE);
   }

   if (bson) {
      *bson = b;
   }

   RETURN(!!b);
}
Example #2
0
bool
_mongoc_cursor_next (mongoc_cursor_t  *cursor,
                     const bson_t    **bson)
{
   const bson_t *b;
   bool eof;

   ENTRY;

   BSON_ASSERT (cursor);

   if (bson) {
      *bson = NULL;
   }

   if (cursor->done || cursor->failed) {
      bson_set_error (&cursor->error,
                      MONGOC_ERROR_CURSOR,
                      MONGOC_ERROR_CURSOR_INVALID_CURSOR,
                      "Cannot advance a completed or failed cursor.");
      RETURN (false);
   }

   /*
    * We cannot proceed if another cursor is receiving results in exhaust mode.
    */
   if (cursor->client->in_exhaust && !cursor->in_exhaust) {
      bson_set_error (&cursor->error,
                      MONGOC_ERROR_CLIENT,
                      MONGOC_ERROR_CLIENT_IN_EXHAUST,
                      "Another cursor derived from this client is in exhaust.");
      cursor->failed = true;
      RETURN (false);
   }

   /*
    * If we reached our limit, make sure we mark this as done and do not try to
    * make further progress.
    */
   if (cursor->limit && cursor->count >= cursor->limit) {
      cursor->done = true;
      RETURN (false);
   }

   /*
    * Try to read the next document from the reader if it exists, we might
    * get NULL back and EOF, in which case we need to submit a getmore.
    */
   if (cursor->reader) {
      eof = false;
      b = bson_reader_read (cursor->reader, &eof);
      cursor->end_of_event = eof;
      if (b) {
         GOTO (complete);
      }
   }

   /*
    * Check to see if we need to send a GET_MORE for more results.
    */
   if (!cursor->sent) {
      if (!_mongoc_cursor_query (cursor)) {
         RETURN (false);
      }
   } else if (BSON_UNLIKELY (cursor->end_of_event) && cursor->rpc.reply.cursor_id) {
      if (!_mongoc_cursor_get_more (cursor)) {
         RETURN (false);
      }
   }

   eof = false;
   b = bson_reader_read (cursor->reader, &eof);
   cursor->end_of_event = eof;

complete:
   cursor->done = (cursor->end_of_event &&
                   ((cursor->in_exhaust && !cursor->rpc.reply.cursor_id) ||
                    (!b && !(cursor->flags & MONGOC_QUERY_TAILABLE_CURSOR))));

   /*
    * Do a supplimental check to see if we had a corrupted reply in the
    * document stream.
    */
   if (!b && !eof) {
      cursor->failed = true;
      bson_set_error (&cursor->error,
                      MONGOC_ERROR_CURSOR,
                      MONGOC_ERROR_PROTOCOL_INVALID_REPLY,
                      "The reply was corrupt.");
      RETURN (false);
   }

   if (bson) {
      *bson = b;
   }

   RETURN (!!b);
}