Skip to content

Commit 87fbd00

Browse files
committed
PHPC-1042: Support options array for BulkWrite, Command, and Query execute methods
1 parent d225060 commit 87fbd00

24 files changed

+901
-39
lines changed

php_phongo.c

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -448,13 +448,109 @@ mongoc_bulk_operation_t *phongo_bulkwrite_init(zend_bool ordered) { /* {{{ */
448448
return mongoc_bulk_operation_new(ordered);
449449
} /* }}} */
450450

451-
bool phongo_execute_write(mongoc_client_t *client, const char *namespace, php_phongo_bulkwrite_t *bulk_write, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
451+
#define PHONGO_WRITECONCERN_ALLOWED 0x01
452+
#define PHONGO_READPREFERENCE_ALLOWED 0x02
453+
454+
static int process_read_preference(zval *option, zval **zreadPreference TSRMLS_DC)
455+
{
456+
if (Z_TYPE_P(option) == IS_OBJECT && instanceof_function(Z_OBJCE_P(option), php_phongo_readpreference_ce TSRMLS_CC)) {
457+
*zreadPreference = option;
458+
} else {
459+
phongo_throw_exception(
460+
PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC,
461+
"Expected 'readPreference' option to be 'MongoDB\\Driver\\ReadPreference', %s given",
462+
zend_get_type_by_const(Z_TYPE_P(option))
463+
);
464+
return false;
465+
}
466+
return true;
467+
}
468+
469+
static int process_write_concern(zval *option, zval **zwriteConcern TSRMLS_DC)
470+
{
471+
if (Z_TYPE_P(option) == IS_OBJECT && instanceof_function(Z_OBJCE_P(option), php_phongo_writeconcern_ce TSRMLS_CC)) {
472+
*zwriteConcern = option;
473+
} else {
474+
phongo_throw_exception(
475+
PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC,
476+
"Expected 'writeConcern' option to be 'MongoDB\\Driver\\WriteConcern', %s given",
477+
zend_get_type_by_const(Z_TYPE_P(option))
478+
);
479+
return false;
480+
}
481+
return true;
482+
}
483+
484+
static int phongo_execute_parse_options(zval *options, int flags, zval **zreadPreference, zval **zwriteConcern TSRMLS_DC)
485+
{
486+
if (options && Z_TYPE_P(options) == IS_ARRAY) {
487+
HashTable *ht_data = HASH_OF(options);
488+
#if PHP_VERSION_ID >= 70000
489+
zend_string *string_key = NULL;
490+
zend_ulong num_key = 0;
491+
zval *option;
492+
493+
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, option) {
494+
if (!string_key) {
495+
continue;
496+
}
497+
498+
if ((!strcasecmp(ZSTR_VAL(string_key), "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
499+
if (!process_read_preference(option, zreadPreference)) {
500+
return false;
501+
}
502+
} else if ((!strcasecmp(ZSTR_VAL(string_key), "writeConcern")) && (flags & PHONGO_WRITECONCERN_ALLOWED)) {
503+
if (!process_write_concern(option, zwriteConcern)) {
504+
return false;
505+
}
506+
} else {
507+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Unknown option '%s'", ZSTR_VAL(string_key));
508+
return false;
509+
}
510+
} ZEND_HASH_FOREACH_END();
511+
#else
512+
HashPosition pos;
513+
zval **option;
514+
515+
for (zend_hash_internal_pointer_reset_ex(ht_data, &pos);
516+
zend_hash_get_current_data_ex(ht_data, (void **) &option, &pos) == SUCCESS;
517+
zend_hash_move_forward_ex(ht_data, &pos)) {
518+
char *string_key = NULL;
519+
uint string_key_len = 0;
520+
ulong num_key = 0;
521+
522+
if (HASH_KEY_IS_STRING != zend_hash_get_current_key_ex(ht_data, &string_key, &string_key_len, &num_key, 0, &pos)) {
523+
continue;
524+
}
525+
526+
/* URI options are case-insensitive */
527+
if ((!strcasecmp(string_key, "readPreference")) && (flags & PHONGO_READPREFERENCE_ALLOWED)) {
528+
if (!process_read_preference(*option, zreadPreference TSRMLS_CC)) {
529+
return false;
530+
}
531+
} else if ((!strcasecmp(string_key, "writeConcern")) && (flags & PHONGO_WRITECONCERN_ALLOWED)) {
532+
if (!process_write_concern(*option, zwriteConcern TSRMLS_CC)) {
533+
return false;
534+
}
535+
} else {
536+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Unknown option '%s'", string_key);
537+
return false;
538+
}
539+
}
540+
#endif
541+
}
542+
return true;
543+
}
544+
545+
bool phongo_execute_write(mongoc_client_t *client, const char *namespace, php_phongo_bulkwrite_t *bulk_write, zval *options, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
452546
{
453547
bson_error_t error;
454548
int success;
455549
bson_t reply = BSON_INITIALIZER;
456550
mongoc_bulk_operation_t *bulk = bulk_write->bulk;
457551
php_phongo_writeresult_t *writeresult;
552+
zval *zwriteConcern = NULL;
553+
const mongoc_write_concern_t *write_concern;
458554

459555
if (bulk_write->executed) {
460556
phongo_throw_exception(PHONGO_ERROR_WRITE_FAILED TSRMLS_CC, "BulkWrite objects may only be executed once and this instance has already been executed");
@@ -466,12 +562,20 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, php_ph
466562
return false;
467563
}
468564

565+
/* FIXME: Legacy way of specifying the writeConcern option into this function */
566+
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_writeconcern_ce TSRMLS_CC)) {
567+
zwriteConcern = options;
568+
} else if (!phongo_execute_parse_options(options, PHONGO_WRITECONCERN_ALLOWED, NULL, &zwriteConcern TSRMLS_CC)) {
569+
return false;
570+
}
571+
469572
mongoc_bulk_operation_set_database(bulk, bulk_write->database);
470573
mongoc_bulk_operation_set_collection(bulk, bulk_write->collection);
471574
mongoc_bulk_operation_set_client(bulk, client);
472575

473576
/* If a write concern was not specified, libmongoc will use the client's
474577
* write concern; however, we should still fetch it for the write result. */
578+
write_concern = phongo_write_concern_from_zval(zwriteConcern TSRMLS_CC);
475579
if (write_concern) {
476580
mongoc_bulk_operation_set_write_concern(bulk, write_concern);
477581
} else {
@@ -542,13 +646,14 @@ static bool phongo_advance_cursor_and_check_for_error(mongoc_cursor_t *cursor TS
542646
return true;
543647
}
544648

545-
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) /* {{{ */
649+
int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *zquery, zval *options, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
546650
{
547651
const php_phongo_query_t *query;
548652
mongoc_cursor_t *cursor;
549653
char *dbname;
550654
char *collname;
551655
mongoc_collection_t *collection;
656+
zval *zreadPreference = NULL;
552657

553658
if (!phongo_split_namespace(namespace, &dbname, &collname)) {
554659
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s: %s", "Invalid namespace provided", namespace);
@@ -564,6 +669,13 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, zval *z
564669
mongoc_collection_set_read_concern(collection, query->read_concern);
565670
}
566671

672+
/* FIXME: Legacy way of specifying the readPreference option into this function */
673+
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
674+
zreadPreference = options;
675+
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, &zreadPreference, NULL TSRMLS_CC)) {
676+
return false;
677+
}
678+
567679
cursor = mongoc_collection_find_with_opts(collection, query->filter, query->opts, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC));
568680
mongoc_collection_destroy(collection);
569681

@@ -603,7 +715,7 @@ static bson_t *create_wrapped_command_envelope(const char *db, bson_t *reply)
603715
return tmp;
604716
}
605717

606-
static int phongo_do_select_server(mongoc_client_t *client, bson_t *opts, zval *zreadPreference, int server_id)
718+
static int phongo_do_select_server(mongoc_client_t *client, bson_t *opts, zval *zreadPreference, int server_id TSRMLS_DC)
607719
{
608720
bson_error_t error;
609721
uint32_t selected_server_id;
@@ -632,7 +744,7 @@ static int phongo_do_select_server(mongoc_client_t *client, bson_t *opts, zval *
632744
return selected_server_id;
633745
}
634746

635-
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) /* {{{ */
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) /* {{{ */
636748
{
637749
const php_phongo_command_t *command;
638750
bson_iter_t iter;
@@ -641,17 +753,28 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, zval *zcomma
641753
bson_t *opts;
642754
mongoc_cursor_t *cmd_cursor;
643755
uint32_t selected_server_id;
756+
zval *zreadPreference = NULL;
644757

645758
command = Z_COMMAND_OBJ_P(zcommand);
646759

647760
opts = bson_new();
648761

649-
selected_server_id = phongo_do_select_server(client, opts, zreadPreference, server_id);
762+
/* FIXME: Legacy way of specifying the readPreference option into this function */
763+
if (options && Z_TYPE_P(options) == IS_OBJECT && instanceof_function(Z_OBJCE_P(options), php_phongo_readpreference_ce TSRMLS_CC)) {
764+
zreadPreference = options;
765+
} else if (!phongo_execute_parse_options(options, PHONGO_READPREFERENCE_ALLOWED, &zreadPreference, NULL TSRMLS_CC)) {
766+
return false;
767+
}
768+
769+
selected_server_id = phongo_do_select_server(client, opts, zreadPreference, server_id TSRMLS_CC);
650770
if (!selected_server_id) {
651771
bson_free(opts);
652772
return false;
653773
}
654774

775+
/* Although "opts" already always includes the serverId option, the read
776+
* preference is added to the command parts, which is relevant for mongos
777+
* command construction. */
655778
if (!mongoc_client_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference TSRMLS_CC), opts, &reply, &error)) {
656779
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
657780
bson_free(opts);

php_phongo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void phongo_readconcern_init (zval *return_value, const
118118
void phongo_readpreference_init (zval *return_value, const mongoc_read_prefs_t *read_prefs TSRMLS_DC);
119119
void phongo_writeconcern_init (zval *return_value, const mongoc_write_concern_t *write_concern TSRMLS_DC);
120120
mongoc_bulk_operation_t* phongo_bulkwrite_init (zend_bool ordered);
121-
bool phongo_execute_write (mongoc_client_t *client, const char *namespace, php_phongo_bulkwrite_t *bulk_write, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
121+
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);
122122
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);
123123
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);
124124

src/MongoDB/Manager.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -283,69 +283,69 @@ static PHP_METHOD(Manager, __construct)
283283
}
284284
} /* }}} */
285285

286-
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeCommand(string $db, MongoDB\Driver\Command $command[, MongoDB\Driver\ReadPreference $readPreference = null])
286+
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeCommand(string $db, MongoDB\Driver\Command $command[, array $options = null])
287287
Execute a Command */
288288
static PHP_METHOD(Manager, executeCommand)
289289
{
290290
php_phongo_manager_t *intern;
291291
char *db;
292292
phongo_zpp_char_len db_len;
293293
zval *command;
294-
zval *readPreference = NULL;
294+
zval *options = NULL;
295295
DECLARE_RETURN_VALUE_USED
296296
SUPPRESS_UNUSED_WARNING(return_value_ptr)
297297

298-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &db, &db_len, &command, php_phongo_command_ce, &readPreference, php_phongo_readpreference_ce) == FAILURE) {
298+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) {
299299
return;
300300
}
301301

302302
intern = Z_MANAGER_OBJ_P(getThis());
303303

304-
phongo_execute_command(intern->client, db, command, readPreference, -1, return_value, return_value_used TSRMLS_CC);
304+
phongo_execute_command(intern->client, db, command, options, -1, return_value, return_value_used TSRMLS_CC);
305305
} /* }}} */
306306

307-
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeQuery(string $namespace, MongoDB\Driver\Query $query[, MongoDB\Driver\ReadPreference $readPreference = null])
307+
/* {{{ proto MongoDB\Driver\Cursor MongoDB\Driver\Manager::executeQuery(string $namespace, MongoDB\Driver\Query $query[, array $options = null])
308308
Execute a Query */
309309
static PHP_METHOD(Manager, executeQuery)
310310
{
311311
php_phongo_manager_t *intern;
312312
char *namespace;
313313
phongo_zpp_char_len namespace_len;
314314
zval *query;
315-
zval *readPreference = NULL;
315+
zval *options = NULL;
316316
DECLARE_RETURN_VALUE_USED
317317
SUPPRESS_UNUSED_WARNING(return_value_ptr)
318318

319-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &namespace, &namespace_len, &query, php_phongo_query_ce, &readPreference, php_phongo_readpreference_ce) == FAILURE) {
319+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &namespace, &namespace_len, &query, php_phongo_query_ce, &options) == FAILURE) {
320320
return;
321321
}
322322

323323
intern = Z_MANAGER_OBJ_P(getThis());
324324

325-
phongo_execute_query(intern->client, namespace, query, readPreference, -1, return_value, return_value_used TSRMLS_CC);
325+
phongo_execute_query(intern->client, namespace, query, options, -1, return_value, return_value_used TSRMLS_CC);
326326
} /* }}} */
327327

328-
/* {{{ proto MongoDB\Driver\WriteResult MongoDB\Driver\Manager::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $zbulk[, MongoDB\Driver\WriteConcern $writeConcern = null])
328+
/* {{{ proto MongoDB\Driver\WriteResult MongoDB\Driver\Manager::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $zbulk[, array $options = null])
329329
Executes a BulkWrite (i.e. any number of insert, update, and delete ops) */
330330
static PHP_METHOD(Manager, executeBulkWrite)
331331
{
332332
php_phongo_manager_t *intern;
333333
char *namespace;
334334
phongo_zpp_char_len namespace_len;
335335
zval *zbulk;
336-
zval *zwrite_concern = NULL;
336+
zval *options = NULL;
337337
php_phongo_bulkwrite_t *bulk;
338338
DECLARE_RETURN_VALUE_USED
339339
SUPPRESS_UNUSED_WARNING(return_value_ptr)
340340

341-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &namespace, &namespace_len, &zbulk, php_phongo_bulkwrite_ce, &zwrite_concern, php_phongo_writeconcern_ce) == FAILURE) {
341+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &namespace, &namespace_len, &zbulk, php_phongo_bulkwrite_ce, &options) == FAILURE) {
342342
return;
343343
}
344344

345345
intern = Z_MANAGER_OBJ_P(getThis());
346346
bulk = Z_BULKWRITE_OBJ_P(zbulk);
347347

348-
phongo_execute_write(intern->client, namespace, bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
348+
phongo_execute_write(intern->client, namespace, bulk, options, -1, return_value, return_value_used TSRMLS_CC);
349349
} /* }}} */
350350

351351
/* {{{ proto MongoDB\Driver\ReadConcern MongoDB\Driver\Manager::getReadConcern()
@@ -485,19 +485,19 @@ ZEND_END_ARG_INFO()
485485
ZEND_BEGIN_ARG_INFO_EX(ai_Manager_executeCommand, 0, 0, 2)
486486
ZEND_ARG_INFO(0, db)
487487
ZEND_ARG_OBJ_INFO(0, command, MongoDB\\Driver\\Command, 0)
488-
ZEND_ARG_OBJ_INFO(0, readPreference, MongoDB\\Driver\\ReadPreference, 1)
488+
ZEND_ARG_INFO(0, options)
489489
ZEND_END_ARG_INFO()
490490

491491
ZEND_BEGIN_ARG_INFO_EX(ai_Manager_executeQuery, 0, 0, 2)
492492
ZEND_ARG_INFO(0, namespace)
493493
ZEND_ARG_OBJ_INFO(0, zquery, MongoDB\\Driver\\Query, 0)
494-
ZEND_ARG_OBJ_INFO(0, readPreference, MongoDB\\Driver\\ReadPreference, 1)
494+
ZEND_ARG_INFO(0, options)
495495
ZEND_END_ARG_INFO()
496496

497497
ZEND_BEGIN_ARG_INFO_EX(ai_Manager_executeBulkWrite, 0, 0, 2)
498498
ZEND_ARG_INFO(0, namespace)
499499
ZEND_ARG_OBJ_INFO(0, zbulk, MongoDB\\Driver\\BulkWrite, 0)
500-
ZEND_ARG_OBJ_INFO(0, writeConcern, MongoDB\\Driver\\WriteConcern, 1)
500+
ZEND_ARG_INFO(0, options)
501501
ZEND_END_ARG_INFO()
502502

503503
ZEND_BEGIN_ARG_INFO_EX(ai_Manager_selectServer, 0, 0, 1)

0 commit comments

Comments
 (0)