diff --git a/php_phongo.c b/php_phongo.c index e68c4a847..2344052d2 100644 --- a/php_phongo.c +++ b/php_phongo.c @@ -604,7 +604,7 @@ bool phongo_parse_read_preference(zval* options, zval** zreadPreference TSRMLS_D * not NULL, the option will be appended. If zsession is not NULL, it will be * assigned to the option. On error, false is returned and an exception is * thrown. */ -static bool phongo_parse_session(zval* options, mongoc_client_t* client, bson_t* mongoc_opts, zval** zsession TSRMLS_DC) /* {{{ */ +bool phongo_parse_session(zval* options, mongoc_client_t* client, bson_t* mongoc_opts, zval** zsession TSRMLS_DC) /* {{{ */ { zval* option = NULL; const mongoc_client_session_t* client_session; diff --git a/php_phongo.h b/php_phongo.h index 1b37a10bf..a689c13c7 100644 --- a/php_phongo.h +++ b/php_phongo.h @@ -147,6 +147,7 @@ const mongoc_write_concern_t* phongo_write_concern_from_zval(zval* zwrite_concer php_phongo_server_description_type_t php_phongo_server_description_type(mongoc_server_description_t* sd); bool phongo_parse_read_preference(zval* options, zval** zreadPreference TSRMLS_DC); +bool phongo_parse_session(zval* options, mongoc_client_t* client, bson_t* mongoc_opts, zval** zsession TSRMLS_DC); zval* php_phongo_prep_legacy_option(zval* options, const char* key, bool* allocated TSRMLS_DC); void php_phongo_prep_legacy_option_free(zval* options TSRMLS_DC); diff --git a/src/MongoDB/Manager.c b/src/MongoDB/Manager.c index 2a406cc86..948f183ca 100644 --- a/src/MongoDB/Manager.c +++ b/src/MongoDB/Manager.c @@ -254,15 +254,28 @@ static void php_phongo_manager_prep_uri_options(zval* options TSRMLS_DC) /* {{{ /* Selects a server for an execute method. If "for_writes" is true, a primary * will be selected. Otherwise, a read preference will be used to select the * server. If zreadPreference is NULL, the client's read preference will be - * used. + * used. If zsession is a session object in a sharded transaction, the session + * will be checked whether it is pinned to a server. If so, that server will be + * selected. Otherwise, server selection * * On success, server_id will be set and the function will return true; * otherwise, false is returned and an exception is thrown. */ -static bool php_phongo_manager_select_server(bool for_writes, zval* zreadPreference, mongoc_client_t* client, uint32_t* server_id TSRMLS_DC) /* {{{ */ +static bool php_phongo_manager_select_server(bool for_writes, zval* zreadPreference, zval* zsession, mongoc_client_t* client, uint32_t* server_id TSRMLS_DC) /* {{{ */ { - const mongoc_read_prefs_t* read_preference = NULL; mongoc_server_description_t* selected_server; - bson_error_t error = { 0 }; + const mongoc_read_prefs_t* read_preference = NULL; + bson_error_t error = { 0 }; + + if (zsession) { + const mongoc_client_session_t* session = Z_SESSION_OBJ_P(zsession)->client_session; + + /* Attempt to fetch server pinned to session */ + if (mongoc_client_session_get_server_id(session) > 0) { + *server_id = mongoc_client_session_get_server_id(session); + + return true; + } + } if (!for_writes) { read_preference = zreadPreference ? phongo_read_preference_from_zval(zreadPreference TSRMLS_CC) : mongoc_client_get_read_prefs(client); @@ -336,6 +349,7 @@ static PHP_METHOD(Manager, executeCommand) zval* options = NULL; bool free_options = false; zval* zreadPreference = NULL; + zval* zsession = NULL; uint32_t server_id = 0; DECLARE_RETURN_VALUE_USED @@ -347,12 +361,17 @@ static PHP_METHOD(Manager, executeCommand) options = php_phongo_prep_legacy_option(options, "readPreference", &free_options TSRMLS_CC); + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + goto cleanup; + } + if (!phongo_parse_read_preference(options, &zreadPreference TSRMLS_CC)) { /* Exception should already have been thrown */ goto cleanup; } - if (!php_phongo_manager_select_server(false, zreadPreference, intern->client, &server_id TSRMLS_CC)) { + if (!php_phongo_manager_select_server(false, zreadPreference, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ goto cleanup; } @@ -376,6 +395,7 @@ static PHP_METHOD(Manager, executeReadCommand) zval* options = NULL; zval* zreadPreference = NULL; uint32_t server_id = 0; + zval* zsession = NULL; DECLARE_RETURN_VALUE_USED if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|a!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) { @@ -384,12 +404,17 @@ static PHP_METHOD(Manager, executeReadCommand) intern = Z_MANAGER_OBJ_P(getThis()); + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + return; + } + if (!phongo_parse_read_preference(options, &zreadPreference TSRMLS_CC)) { /* Exception should already have been thrown */ return; } - if (!php_phongo_manager_select_server(false, zreadPreference, intern->client, &server_id TSRMLS_CC)) { + if (!php_phongo_manager_select_server(false, zreadPreference, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ return; } @@ -407,6 +432,7 @@ static PHP_METHOD(Manager, executeWriteCommand) zval* command; zval* options = NULL; uint32_t server_id = 0; + zval* zsession = NULL; DECLARE_RETURN_VALUE_USED if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|a!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) { @@ -415,7 +441,12 @@ static PHP_METHOD(Manager, executeWriteCommand) intern = Z_MANAGER_OBJ_P(getThis()); - if (!php_phongo_manager_select_server(true, NULL, intern->client, &server_id TSRMLS_CC)) { + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + return; + } + + if (!php_phongo_manager_select_server(true, NULL, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ return; } @@ -433,6 +464,7 @@ static PHP_METHOD(Manager, executeReadWriteCommand) zval* command; zval* options = NULL; uint32_t server_id = 0; + zval* zsession = NULL; DECLARE_RETURN_VALUE_USED if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|a!", &db, &db_len, &command, php_phongo_command_ce, &options) == FAILURE) { @@ -441,7 +473,12 @@ static PHP_METHOD(Manager, executeReadWriteCommand) intern = Z_MANAGER_OBJ_P(getThis()); - if (!php_phongo_manager_select_server(true, NULL, intern->client, &server_id TSRMLS_CC)) { + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + return; + } + + if (!php_phongo_manager_select_server(true, NULL, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ return; } @@ -461,6 +498,7 @@ static PHP_METHOD(Manager, executeQuery) bool free_options = false; zval* zreadPreference = NULL; uint32_t server_id = 0; + zval* zsession = NULL; DECLARE_RETURN_VALUE_USED if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &namespace, &namespace_len, &query, php_phongo_query_ce, &options) == FAILURE) { @@ -471,12 +509,17 @@ static PHP_METHOD(Manager, executeQuery) options = php_phongo_prep_legacy_option(options, "readPreference", &free_options TSRMLS_CC); + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + goto cleanup; + } + if (!phongo_parse_read_preference(options, &zreadPreference TSRMLS_CC)) { /* Exception should already have been thrown */ goto cleanup; } - if (!php_phongo_manager_select_server(false, zreadPreference, intern->client, &server_id TSRMLS_CC)) { + if (!php_phongo_manager_select_server(false, zreadPreference, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ goto cleanup; } @@ -501,6 +544,7 @@ static PHP_METHOD(Manager, executeBulkWrite) zval* options = NULL; bool free_options = false; uint32_t server_id = 0; + zval* zsession = NULL; DECLARE_RETURN_VALUE_USED if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|z!", &namespace, &namespace_len, &zbulk, php_phongo_bulkwrite_ce, &options) == FAILURE) { @@ -512,7 +556,12 @@ static PHP_METHOD(Manager, executeBulkWrite) options = php_phongo_prep_legacy_option(options, "writeConcern", &free_options TSRMLS_CC); - if (!php_phongo_manager_select_server(true, NULL, intern->client, &server_id TSRMLS_CC)) { + if (!phongo_parse_session(options, intern->client, NULL, &zsession TSRMLS_CC)) { + /* Exception should already have been thrown */ + return; + } + + if (!php_phongo_manager_select_server(true, NULL, zsession, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ goto cleanup; } @@ -628,7 +677,7 @@ static PHP_METHOD(Manager, selectServer) return; } - if (!php_phongo_manager_select_server(false, zreadPreference, intern->client, &server_id TSRMLS_CC)) { + if (!php_phongo_manager_select_server(false, zreadPreference, NULL, intern->client, &server_id TSRMLS_CC)) { /* Exception should already have been thrown */ return; } diff --git a/src/MongoDB/Session.c b/src/MongoDB/Session.c index f0063593e..cb02425ce 100644 --- a/src/MongoDB/Session.c +++ b/src/MongoDB/Session.c @@ -38,18 +38,6 @@ zend_class_entry* php_phongo_session_ce; return; \ } -static bool php_phongo_topology_is_sharded_cluster(mongoc_client_t* client) -{ - mongoc_server_description_t* sd; - bool ret; - - sd = mongoc_client_select_server(client, true, NULL, NULL); - ret = (sd && !strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_MONGOS].name)); - mongoc_server_description_destroy(sd); - - return ret; -} - static bool php_phongo_session_get_timestamp_parts(zval* obj, uint32_t* timestamp, uint32_t* increment TSRMLS_DC) { bool retval = false; @@ -366,11 +354,6 @@ static PHP_METHOD(Session, startTransaction) return; } - if (php_phongo_topology_is_sharded_cluster(mongoc_client_session_get_client(intern->client_session))) { - phongo_throw_exception(PHONGO_ERROR_RUNTIME TSRMLS_CC, "PHP MongoDB driver %s does not support running multi-document transactions on sharded clusters", PHP_MONGODB_VERSION); - return; - } - if (!mongoc_client_session_start_transaction(intern->client_session, txn_options, &error)) { phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC); } diff --git a/tests/session/session-startTransaction_error-004.phpt b/tests/session/session-startTransaction_error-004.phpt deleted file mode 100644 index cf8b5c024..000000000 --- a/tests/session/session-startTransaction_error-004.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -MongoDB\Driver\Session::startTransaction() does not support sharded clusters ---SKIPIF-- - - - - ---FILE-- -startSession(); - -echo throws(function() use ($session) { - $session->startTransaction(); -}, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; - -?> -===DONE=== - ---EXPECTF-- -OK: Got MongoDB\Driver\Exception\RuntimeException -PHP MongoDB driver %s does not support running multi-document transactions on sharded clusters -===DONE===