Skip to content

Commit a939e39

Browse files
committed
PHPC-834: Add Read, ReadWrite, and Write command execute methods
1 parent 619cee8 commit a939e39

File tree

4 files changed

+255
-21
lines changed

4 files changed

+255
-21
lines changed

php_phongo.c

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,62 @@ mongoc_bulk_operation_t *phongo_bulkwrite_init(zend_bool ordered) { /* {{{ */
451451
#define PHONGO_WRITECONCERN_ALLOWED 0x01
452452
#define PHONGO_READPREFERENCE_ALLOWED 0x02
453453

454+
/* Appends a document field for the given opts document and key. Returns true on
455+
* success; otherwise, false is returned and an exception is thrown. */
456+
static bool php_phongo_command_opts_append_document(bson_t *opts, const char *opts_key, zval *zarr, const char *zarr_key TSRMLS_DC) /* {{{ */
457+
{
458+
zval *value = php_array_fetch(zarr, zarr_key);
459+
bson_t b = BSON_INITIALIZER;
460+
461+
if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_ARRAY) {
462+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected \"%s\" option to be array or object, %s given", zarr_key, zend_get_type_by_const(Z_TYPE_P(value)));
463+
return false;
464+
}
465+
466+
php_phongo_zval_to_bson(value, PHONGO_BSON_NONE, &b, NULL TSRMLS_CC);
467+
468+
if (EG(exception)) {
469+
bson_destroy(&b);
470+
return false;
471+
}
472+
473+
if (!BSON_APPEND_DOCUMENT(opts, opts_key, &b)) {
474+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"%s\" option", opts_key);
475+
bson_destroy(&b);
476+
return false;
477+
}
478+
479+
bson_destroy(&b);
480+
return true;
481+
} /* }}} */
482+
483+
484+
static int process_collation(zval *option, bson_t *mongoc_opts TSRMLS_DC)
485+
{
486+
return php_phongo_command_opts_append_document(mongoc_opts, "collation", option, "collation" TSRMLS_CC);
487+
}
488+
489+
static int process_read_concern(zval *option, bson_t *mongoc_opts TSRMLS_DC)
490+
{
491+
if (Z_TYPE_P(option) == IS_OBJECT && instanceof_function(Z_OBJCE_P(option), php_phongo_readconcern_ce TSRMLS_CC)) {
492+
zval zreadConcern;
493+
const mongoc_read_concern_t *read_concern = phongo_read_concern_from_zval(option TSRMLS_CC);
494+
495+
php_phongo_read_concern_to_zval(&zreadConcern, read_concern);
496+
convert_to_object(&zreadConcern);
497+
498+
return php_phongo_command_opts_append_document(mongoc_opts, "readConcern", &zreadConcern, "readConcern" TSRMLS_CC);
499+
} else {
500+
phongo_throw_exception(
501+
PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC,
502+
"Expected 'readConcern' option to be 'MongoDB\\Driver\\ReadPreference', %s given",
503+
zend_get_type_by_const(Z_TYPE_P(option))
504+
);
505+
return false;
506+
}
507+
return true;
508+
}
509+
454510
static int process_read_preference(zval *option, zval **zreadPreference TSRMLS_DC)
455511
{
456512
if (Z_TYPE_P(option) == IS_OBJECT && instanceof_function(Z_OBJCE_P(option), php_phongo_readpreference_ce TSRMLS_CC)) {
@@ -481,26 +537,35 @@ static int process_write_concern(zval *option, zval **zwriteConcern TSRMLS_DC)
481537
return true;
482538
}
483539

484-
static int phongo_execute_parse_options(zval *options, int flags, zval **zreadPreference, zval **zwriteConcern TSRMLS_DC)
540+
static int phongo_execute_parse_options(zval *driver_options, int flags, bson_t *mongoc_opts, zval **zreadPreference, zval **zwriteConcern TSRMLS_DC)
485541
{
486-
if (options && Z_TYPE_P(options) == IS_ARRAY) {
487-
HashTable *ht_data = HASH_OF(options);
542+
if (driver_options && Z_TYPE_P(driver_options) == IS_ARRAY) {
543+
HashTable *ht_data = HASH_OF(driver_options);
488544
#if PHP_VERSION_ID >= 70000
489545
zend_string *string_key = NULL;
490546
zend_ulong num_key = 0;
491-
zval *option;
547+
zval *driver_option;
492548

493-
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, option) {
549+
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, driver_option) {
494550
if (!string_key) {
495551
continue;
496552
}
497553

498-
if ((!strcasecmp(ZSTR_VAL(string_key), "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
499-
if (!process_read_preference(option, zreadPreference)) {
554+
/* URI options are case-insensitive */
555+
if (!strcasecmp(ZSTR_VAL(string_key), "collation")) {
556+
if (!process_collation(driver_option, mongoc_opts)) {
557+
return false;
558+
}
559+
} else if (!strcasecmp(ZSTR_VAL(string_key), "readConcern")) {
560+
if (!process_read_concern(driver_option, mongoc_opts)) {
561+
return false;
562+
}
563+
} else if ((!strcasecmp(ZSTR_VAL(string_key), "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
564+
if (!process_read_preference(driver_option, zreadPreference)) {
500565
return false;
501566
}
502567
} else if ((!strcasecmp(ZSTR_VAL(string_key), "writeConcern")) && (flags & PHONGO_WRITECONCERN_ALLOWED)) {
503-
if (!process_write_concern(option, zwriteConcern)) {
568+
if (!process_write_concern(driver_option, zwriteConcern)) {
504569
return false;
505570
}
506571
} else {
@@ -510,10 +575,10 @@ static int phongo_execute_parse_options(zval *options, int flags, zval **zreadPr
510575
} ZEND_HASH_FOREACH_END();
511576
#else
512577
HashPosition pos;
513-
zval **option;
578+
zval **driver_option;
514579

515580
for (zend_hash_internal_pointer_reset_ex(ht_data, &pos);
516-
zend_hash_get_current_data_ex(ht_data, (void **) &option, &pos) == SUCCESS;
581+
zend_hash_get_current_data_ex(ht_data, (void **) &driver_option, &pos) == SUCCESS;
517582
zend_hash_move_forward_ex(ht_data, &pos)) {
518583
char *string_key = NULL;
519584
uint string_key_len = 0;
@@ -524,12 +589,20 @@ static int phongo_execute_parse_options(zval *options, int flags, zval **zreadPr
524589
}
525590

526591
/* URI options are case-insensitive */
527-
if ((!strcasecmp(string_key, "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
528-
if (!process_read_preference(*option, zreadPreference TSRMLS_CC)) {
592+
if (!strcasecmp(string_key, "collation")) {
593+
if (!process_collation(*driver_option, mongoc_opts)) {
594+
return false;
595+
}
596+
} else if (!strcasecmp(string_key, "readConcern")) {
597+
if (!process_read_concern(*driver_option, mongoc_opts)) {
598+
return false;
599+
}
600+
} else if ((!strcasecmp(string_key, "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
601+
if (!process_read_preference(*driver_option, zreadPreference TSRMLS_CC)) {
529602
return false;
530603
}
531604
} else if ((!strcasecmp(string_key, "writeConcern")) && (flags & PHONGO_WRITECONCERN_ALLOWED)) {
532-
if (!process_write_concern(*option, zwriteConcern TSRMLS_CC)) {
605+
if (!process_write_concern(*driver_option, zwriteConcern TSRMLS_CC)) {
533606
return false;
534607
}
535608
} else {
@@ -565,7 +638,7 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, php_ph
565638
/* FIXME: Legacy way of specifying the writeConcern option into this function */
566639
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_writeconcern_ce TSRMLS_CC)) {
567640
zwriteConcern = options;
568-
} else if (!phongo_execute_parse_options(options, PHONGO_WRITECONCERN_ALLOWED, NULL, &zwriteConcern TSRMLS_CC)) {
641+
} else if (!phongo_execute_parse_options(options, PHONGO_WRITECONCERN_ALLOWED, NULL, NULL, &zwriteConcern TSRMLS_CC)) {
569642
return false;
570643
}
571644

@@ -672,7 +745,7 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *z
672745
/* FIXME: Legacy way of specifying the readPreference option into this function */
673746
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
674747
zreadPreference = options;
675-
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, &zreadPreference, NULL TSRMLS_CC)) {
748+
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, NULL, &zreadPreference, NULL TSRMLS_CC)) {
676749
return false;
677750
}
678751

@@ -744,7 +817,7 @@ static int phongo_do_select_server(mongoc_client_t *client, bson_t *opts, zval *
744817
return selected_server_id;
745818
}
746819

747-
int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcommand, zval *options, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
820+
int phongo_execute_command(mongoc_client_t *client, php_phongo_command_type_t type, const char *db, zval *zcommand, zval *options, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
748821
{
749822
const php_phongo_command_t *command;
750823
bson_iter_t iter;
@@ -754,6 +827,7 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
754827
mongoc_cursor_t *cmd_cursor;
755828
uint32_t selected_server_id;
756829
zval *zreadPreference = NULL;
830+
int result;
757831

758832
command = Z_COMMAND_OBJ_P(zcommand);
759833

@@ -762,7 +836,7 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
762836
/* FIXME: Legacy way of specifying the readPreference option into this function */
763837
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
764838
zreadPreference = options;
765-
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, &zreadPreference, NULL TSRMLS_CC)) {
839+
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, opts, &zreadPreference, NULL TSRMLS_CC)) {
766840
return false;
767841
}
768842

@@ -775,7 +849,24 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
775849
/* Although "opts" already always includes the serverId option, the read
776850
* preference is added to the command parts, which is relevant for mongos
777851
* command construction. */
778-
if (!mongoc_client_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC), opts, &reply, &error)) {
852+
switch (type) {
853+
case PHONGO_COMMAND_RAW:
854+
result = mongoc_client_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC), opts, &reply, &error);
855+
break;
856+
case PHONGO_COMMAND_READ:
857+
result = mongoc_client_read_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC), opts, &reply, &error);
858+
break;
859+
case PHONGO_COMMAND_WRITE:
860+
result = mongoc_client_write_command_with_opts(client, db, command->bson, opts, &reply, &error);
861+
break;
862+
case PHONGO_COMMAND_READ_WRITE:
863+
result = mongoc_client_read_write_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC), opts, &reply, &error);
864+
break;
865+
default:
866+
/* Should never happen, but if it does: abort */
867+
assert(false);
868+
}
869+
if (!result) {
779870
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
780871
bson_free(opts);
781872
return false;

php_phongo.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ void phongo_throw_exception(php_phongo_error_domain_t domain TSRMLS_DC, const ch
111111
;
112112
void phongo_throw_exception_from_bson_error_t(bson_error_t *error TSRMLS_DC);
113113

114+
/* This enum is used for libmongoc function selection for the phongo_execute_command types */
115+
typedef enum {
116+
PHONGO_COMMAND_RAW = 1,
117+
PHONGO_COMMAND_READ = 2,
118+
PHONGO_COMMAND_WRITE = 3,
119+
PHONGO_COMMAND_READ_WRITE = 4
120+
} php_phongo_command_type_t;
121+
114122
zend_object_handlers *phongo_get_std_object_handlers(void);
115123

116124
void phongo_server_init (zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC);
@@ -119,7 +127,7 @@ void phongo_readpreference_init (zval *return_value, const
119127
void phongo_writeconcern_init (zval *return_value, const mongoc_write_concern_t *write_concern TSRMLS_DC);
120128
mongoc_bulk_operation_t* phongo_bulkwrite_init (zend_bool ordered);
121129
bool phongo_execute_write (mongoc_client_t *client, const char *namespace, php_phongo_bulkwrite_t *bulk_write, zval *zwriteConcern, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
122-
int phongo_execute_command (mongoc_client_t *client, const char *db, zval *zcommand, zval *zreadPreference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
130+
int phongo_execute_command (mongoc_client_t *client, php_phongo_command_type_t type, const char *db, zval *zcommand, zval *zreadPreference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
123131
int phongo_execute_query (mongoc_client_t *client, const char *namespace, zval *zquery, zval *zreadPreference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
124132

125133
const mongoc_read_concern_t* phongo_read_concern_from_zval (zval *zread_concern TSRMLS_DC);

src/MongoDB/Manager.c

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,70 @@ static PHP_METHOD(Manager, executeCommand)
301301

302302
intern = Z_MANAGER_OBJ_P(getThis());
303303

304-
phongo_execute_command(intern->client, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
304+
phongo_execute_command(intern->client, PHONGO_COMMAND_RAW, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
305+
} /* }}} */
306+
307+
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeReadCommand(string $db, MongoDB\Driver\Command $command[, array $options = null])
308+
Execute a ReadCommand */
309+
static PHP_METHOD(Manager, executeReadCommand)
310+
{
311+
php_phongo_manager_t *intern;
312+
char *db;
313+
phongo_zpp_char_len db_len;
314+
zval *command;
315+
zval *options = NULL;
316+
DECLARE_RETURN_VALUE_USED
317+
SUPPRESS_UNUSED_WARNING(return_value_ptr)
318+
319+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) {
320+
return;
321+
}
322+
323+
intern = Z_MANAGER_OBJ_P(getThis());
324+
325+
phongo_execute_command(intern->client, PHONGO_COMMAND_READ, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
326+
} /* }}} */
327+
328+
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeWriteCommand(string $db, MongoDB\Driver\Command $command[, array $options = null])
329+
Execute a WriteCommand */
330+
static PHP_METHOD(Manager, executeWriteCommand)
331+
{
332+
php_phongo_manager_t *intern;
333+
char *db;
334+
phongo_zpp_char_len db_len;
335+
zval *command;
336+
zval *options = NULL;
337+
DECLARE_RETURN_VALUE_USED
338+
SUPPRESS_UNUSED_WARNING(return_value_ptr)
339+
340+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) {
341+
return;
342+
}
343+
344+
intern = Z_MANAGER_OBJ_P(getThis());
345+
346+
phongo_execute_command(intern->client, PHONGO_COMMAND_WRITE, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
347+
} /* }}} */
348+
349+
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeReadWriteCommand(string $db, MongoDB\Driver\Command $command[, array $options = null])
350+
Execute a ReadWriteCommand */
351+
static PHP_METHOD(Manager, executeReadWriteCommand)
352+
{
353+
php_phongo_manager_t *intern;
354+
char *db;
355+
phongo_zpp_char_len db_len;
356+
zval *command;
357+
zval *options = NULL;
358+
DECLARE_RETURN_VALUE_USED
359+
SUPPRESS_UNUSED_WARNING(return_value_ptr)
360+
361+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) {
362+
return;
363+
}
364+
365+
intern = Z_MANAGER_OBJ_P(getThis());
366+
367+
phongo_execute_command(intern->client, PHONGO_COMMAND_READ_WRITE, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
305368
} /* }}} */
306369

307370
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeQuery(string $namespace, MongoDB\Driver\Query $query[, array $options = null])
@@ -510,6 +573,9 @@ ZEND_END_ARG_INFO()
510573
static zend_function_entry php_phongo_manager_me[] = {
511574
PHP_ME(Manager, __construct, ai_Manager___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
512575
PHP_ME(Manager, executeCommand, ai_Manager_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
576+
PHP_ME(Manager, executeReadCommand, ai_Manager_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
577+
PHP_ME(Manager, executeWriteCommand, ai_Manager_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
578+
PHP_ME(Manager, executeReadWriteCommand, ai_Manager_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
513579
PHP_ME(Manager, executeQuery, ai_Manager_executeQuery, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
514580
PHP_ME(Manager, executeBulkWrite, ai_Manager_executeBulkWrite, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
515581
PHP_ME(Manager, getReadConcern, ai_Manager_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)

0 commit comments

Comments
 (0)