Skip to content

Commit 18e2e2d

Browse files
committed
PHPC-602: Create command cursors with mongoc_cursor_new_from_command_reply()
This also refactors some common error-checking code in phongo_execute_query() and phongo_execute_command() into the phongo_advance_cursor_and_check_for_error() function.
1 parent 6ed383e commit 18e2e2d

File tree

1 file changed

+41
-64
lines changed

1 file changed

+41
-64
lines changed

php_phongo.c

Lines changed: 41 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,34 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, mongoc
569569
return success;
570570
} /* }}} */
571571

572+
/* Advance the cursor and return whether there is an error. On error, the cursor
573+
* will be destroyed and an exception will be thrown. */
574+
static bool phongo_advance_cursor_and_check_for_error(mongoc_cursor_t *cursor TSRMLS_DC)
575+
{
576+
const bson_t *doc;
577+
578+
if (!mongoc_cursor_next(cursor, &doc)) {
579+
bson_error_t error;
580+
581+
/* Check for connection related exceptions */
582+
if (EG(exception)) {
583+
mongoc_cursor_destroy(cursor);
584+
return false;
585+
}
586+
587+
/* Could simply be no docs, which is not an error */
588+
if (mongoc_cursor_error(cursor, &error)) {
589+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
590+
mongoc_cursor_destroy(cursor);
591+
return false;
592+
}
593+
}
594+
595+
return true;
596+
}
597+
572598
int phongo_execute_query(mongoc_client_t *client, const char *namespace, const php_phongo_query_t *query, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
573599
{
574-
const bson_t *doc = NULL;
575600
mongoc_cursor_t *cursor;
576601
char *dbname;
577602
char *collname;
@@ -601,22 +626,9 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, const p
601626
if (server_id > 0) {
602627
cursor->server_id = server_id;
603628
}
604-
if (!mongoc_cursor_next(cursor, &doc)) {
605-
bson_error_t error;
606-
607-
/* Check for connection related exceptions */
608-
if (EG(exception)) {
609-
mongoc_cursor_destroy(cursor);
610-
return false;
611-
}
612-
613-
/* Could simply be no docs, which is not an error */
614-
if (mongoc_cursor_error(cursor, &error)) {
615-
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
616-
mongoc_cursor_destroy(cursor);
617-
return false;
618-
}
619629

630+
if (!phongo_advance_cursor_and_check_for_error(cursor TSRMLS_CC)) {
631+
return false;
620632
}
621633

622634
if (!return_value_used) {
@@ -631,73 +643,38 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, const p
631643
int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
632644
{
633645
mongoc_cursor_t *cursor;
634-
const bson_t *doc;
635646
bson_iter_t iter;
636-
bson_iter_t child;
637647

638648

639649
cursor = mongoc_client_command(client, db, MONGOC_QUERY_NONE, 0, 1, 0, command, NULL, read_preference);
640650
if (server_id > 0) {
641651
cursor->server_id = server_id;
642652
}
643653

644-
if (!mongoc_cursor_next(cursor, &doc)) {
645-
bson_error_t error;
646-
647-
/* Check for connection related exceptions */
648-
if (EG(exception)) {
649-
mongoc_cursor_destroy(cursor);
650-
return false;
651-
}
652-
653-
if (mongoc_cursor_error(cursor, &error)) {
654-
mongoc_cursor_destroy(cursor);
655-
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
656-
return false;
657-
}
654+
if (!phongo_advance_cursor_and_check_for_error(cursor TSRMLS_CC)) {
655+
return false;
658656
}
659657

660658
if (!return_value_used) {
661659
mongoc_cursor_destroy(cursor);
662660
return true;
663661
}
664662

665-
/* This code is adapated from _mongoc_cursor_cursorid_prime(), but we avoid
666-
* advancing the cursor, since we are already positioned at the first result
667-
* after the error checking above. */
668-
if (bson_iter_init_find(&iter, doc, "cursor") && BSON_ITER_HOLDS_DOCUMENT(&iter) && bson_iter_recurse(&iter, &child)) {
669-
mongoc_cursor_cursorid_t *cid;
670-
bson_t empty = BSON_INITIALIZER;
671-
672-
_mongoc_cursor_cursorid_init(cursor, &empty);
673-
cursor->limit = 0;
663+
if (bson_iter_init_find(&iter, mongoc_cursor_current(cursor), "cursor") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
664+
mongoc_cursor_t *cmd_cursor;
674665

675-
cid = cursor->iface_data;
676-
cid->in_batch = true;
677-
bson_destroy (&empty);
678-
679-
while (bson_iter_next(&child)) {
680-
if (BSON_ITER_IS_KEY(&child, "id")) {
681-
cursor->rpc.reply.cursor_id = bson_iter_as_int64(&child);
682-
} else if (BSON_ITER_IS_KEY(&child, "ns")) {
683-
const char *ns;
666+
/* According to mongoc_cursor_new_from_command_reply(), the reply bson_t
667+
* is ultimately destroyed on both success and failure. Use bson_copy()
668+
* to create a writable copy of the const bson_t we fetched above. */
669+
cmd_cursor = mongoc_cursor_new_from_command_reply(client, bson_copy(mongoc_cursor_current(cursor)), mongoc_cursor_get_hint(cursor));
670+
mongoc_cursor_destroy(cursor);
684671

685-
ns = bson_iter_utf8(&child, &cursor->nslen);
686-
bson_strncpy(cursor->ns, ns, sizeof cursor->ns);
687-
} else if (BSON_ITER_IS_KEY(&child, "firstBatch")) {
688-
if (BSON_ITER_HOLDS_ARRAY(&child) && bson_iter_recurse(&child, &cid->batch_iter)) {
689-
cid->in_batch = true;
690-
}
691-
}
672+
if (!phongo_advance_cursor_and_check_for_error(cmd_cursor TSRMLS_CC)) {
673+
return false;
692674
}
693675

694-
cursor->is_command = false;
695-
696-
/* The cursor's current element is the command's response document.
697-
* Advance once so that the cursor is positioned at the first document
698-
* within the command cursor's result set.
699-
*/
700-
mongoc_cursor_next(cursor, &doc);
676+
phongo_cursor_init(return_value, cmd_cursor, client TSRMLS_CC);
677+
return true;
701678
}
702679

703680
phongo_cursor_init(return_value, cursor, client TSRMLS_CC);

0 commit comments

Comments
 (0)