Skip to content

Commit 9fd2f10

Browse files
committed
Merge branch 'v1.4'
2 parents ebdf86f + 46711f5 commit 9fd2f10

6 files changed

+298
-20
lines changed

php_phongo.c

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,17 @@ bool phongo_execute_bulk_write(mongoc_client_t* client, const char* namespace, p
644644
return false;
645645
}
646646

647+
/* If a write concern was not specified, libmongoc will use the client's
648+
* write concern; however, we should still fetch it for the write result.
649+
* Additionally, we need to check if an unacknowledged write concern would
650+
* conflict with an explicit session. */
651+
write_concern = zwriteConcern ? Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern : mongoc_client_get_write_concern(client);
652+
653+
if (zsession && !mongoc_write_concern_is_acknowledged(write_concern)) {
654+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Cannot combine \"session\" option with an unacknowledged write concern");
655+
return false;
656+
}
657+
647658
mongoc_bulk_operation_set_database(bulk, bulk_write->database);
648659
mongoc_bulk_operation_set_collection(bulk, bulk_write->collection);
649660
mongoc_bulk_operation_set_client(bulk, client);
@@ -653,13 +664,8 @@ bool phongo_execute_bulk_write(mongoc_client_t* client, const char* namespace, p
653664
mongoc_bulk_operation_set_client_session(bulk, Z_SESSION_OBJ_P(zsession)->client_session);
654665
}
655666

656-
/* If a write concern was not specified, libmongoc will use the client's
657-
* write concern; however, we should still fetch it for the write result. */
658-
write_concern = phongo_write_concern_from_zval(zwriteConcern TSRMLS_CC);
659-
if (write_concern) {
660-
mongoc_bulk_operation_set_write_concern(bulk, write_concern);
661-
} else {
662-
write_concern = mongoc_client_get_write_concern(client);
667+
if (zwriteConcern) {
668+
mongoc_bulk_operation_set_write_concern(bulk, Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern);
663669
}
664670

665671
success = mongoc_bulk_operation_execute(bulk, &reply, &error);
@@ -827,11 +833,12 @@ bool phongo_execute_command(mongoc_client_t* client, php_phongo_command_type_t t
827833
bson_error_t error;
828834
bson_t opts = BSON_INITIALIZER;
829835
mongoc_cursor_t* cmd_cursor;
830-
zval* zreadPreference = NULL;
831-
zval* zsession = NULL;
832-
bool result = false;
833-
bool free_reply = false;
834-
bool free_zsession = false;
836+
zval* zreadPreference = NULL;
837+
zval* zsession = NULL;
838+
bool result = false;
839+
bool free_reply = false;
840+
bool free_zsession = false;
841+
bool is_unacknowledged_write_concern = false;
835842

836843
command = Z_COMMAND_OBJ_P(zcommand);
837844

@@ -850,9 +857,33 @@ bool phongo_execute_command(mongoc_client_t* client, php_phongo_command_type_t t
850857
goto cleanup;
851858
}
852859

853-
/* If an explicit session was not provided, attempt to create an implicit
854-
* client session (ignoring any errors). */
855-
if (!zsession) {
860+
if (type & PHONGO_OPTION_WRITE_CONCERN) {
861+
zval* zwriteConcern = NULL;
862+
863+
if (!phongo_parse_write_concern(options, &opts, &zwriteConcern TSRMLS_CC)) {
864+
/* Exception should already have been thrown */
865+
goto cleanup;
866+
}
867+
868+
/* Determine if the explicit or inherited write concern is
869+
* unacknowledged so that we can ensure it does not conflict with an
870+
* explicit or implicit session. */
871+
if (zwriteConcern) {
872+
is_unacknowledged_write_concern = !mongoc_write_concern_is_acknowledged(Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern);
873+
} else if (type != PHONGO_COMMAND_RAW) {
874+
is_unacknowledged_write_concern = !mongoc_write_concern_is_acknowledged(mongoc_client_get_write_concern(client));
875+
}
876+
}
877+
878+
if (zsession && is_unacknowledged_write_concern) {
879+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Cannot combine \"session\" option with an unacknowledged write concern");
880+
goto cleanup;
881+
}
882+
883+
/* If an explicit session was not provided and the effective write concern
884+
* is not unacknowledged, attempt to create an implicit client session
885+
* (ignoring any errors). */
886+
if (!zsession && !is_unacknowledged_write_concern) {
856887
zsession = phongo_create_implicit_session(client TSRMLS_CC);
857888

858889
if (zsession) {
@@ -865,11 +896,6 @@ bool phongo_execute_command(mongoc_client_t* client, php_phongo_command_type_t t
865896
}
866897
}
867898

868-
if ((type & PHONGO_OPTION_WRITE_CONCERN) && !phongo_parse_write_concern(options, &opts, NULL TSRMLS_CC)) {
869-
/* Exception should already have been thrown */
870-
goto cleanup;
871-
}
872-
873899
if (!BSON_APPEND_INT32(&opts, "serverId", server_id)) {
874900
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"serverId\" option");
875901
goto cleanup;

tests/manager/bug1163-001.phpt

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
--TEST--
2+
PHPC-1163: Unacknowledged write concern should omit implicit session
3+
--XFAIL--
4+
Depends on CDRIVER-2615
5+
--SKIPIF--
6+
<?php if (PHP_INT_SIZE !== 8) { die("skip Can't represent 64-bit ints on a 32-bit platform"); } ?>
7+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
8+
<?php NEEDS('STANDALONE'); ?>
9+
<?php CLEANUP(STANDALONE); ?>
10+
--FILE--
11+
<?php
12+
require_once __DIR__ . "/../utils/basic.inc";
13+
14+
class Test implements MongoDB\Driver\Monitoring\CommandSubscriber
15+
{
16+
public function run()
17+
{
18+
$manager = new MongoDB\Driver\Manager(STANDALONE, ['w' => 0]);
19+
20+
MongoDB\Driver\Monitoring\addSubscriber($this);
21+
22+
$bulk = new MongoDB\Driver\BulkWrite;
23+
$bulk->insert(['x' => 1]);
24+
25+
echo "Testing executeBulkWrite\n";
26+
$manager->executeBulkWrite(NS, $bulk);
27+
28+
$command = new MongoDB\Driver\Command([
29+
'insert' => COLLECTION_NAME,
30+
'documents' => [['x' => 1]],
31+
]);
32+
33+
/* Note: executeCommand() and executeReadCommand() are not tested
34+
* because they do not inherit the client-level write concern. */
35+
36+
echo "\nTesting executeWriteCommand\n";
37+
$manager->executeWriteCommand(DATABASE_NAME, $command);
38+
39+
/* We can safely re-use the insert command with executeReadWriteCommand
40+
* because there is no readConcern to inherit. */
41+
echo "\nTesting executeReadWriteCommand\n";
42+
$manager->executeReadWriteCommand(DATABASE_NAME, $command);
43+
44+
MongoDB\Driver\Monitoring\removeSubscriber($this);
45+
}
46+
47+
public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event)
48+
{
49+
if ($event->getCommandName() === 'insert') {
50+
$command = $event->getCommand();
51+
$hasSession = isset($command->lsid);
52+
$writeConcern = isset($command->writeConcern) ? $command->writeConcern: null;
53+
54+
printf("insert command write concern: %s\n", json_encode($writeConcern));
55+
printf("insert command has session: %s\n", $hasSession ? 'yes' : 'no');
56+
}
57+
}
58+
59+
public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event)
60+
{
61+
}
62+
63+
public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event)
64+
{
65+
}
66+
}
67+
68+
(new Test)->run();
69+
70+
?>
71+
===DONE===
72+
<?php exit(0); ?>
73+
--EXPECT--
74+
Testing executeBulkWrite
75+
insert command write concern: {"w":0}
76+
insert command has session: no
77+
78+
Testing executeWriteCommand
79+
insert command write concern: {"w":0}
80+
insert command has session: no
81+
82+
Testing executeReadWriteCommand
83+
insert command write concern: {"w":0}
84+
insert command has session: no
85+
===DONE===
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
MongoDB\Driver\Manager::executeBulkWrite() cannot combine session with unacknowledged write concern
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php NEEDS_CRYPTO(); ?>
6+
<?php NEEDS('STANDALONE'); ?>
7+
<?php NEEDS_ATLEAST_MONGODB_VERSION(STANDALONE, "3.6"); ?>
8+
--FILE--
9+
<?php
10+
require_once __DIR__ . "/../utils/basic.inc";
11+
12+
echo throws(function() {
13+
$manager = new MongoDB\Driver\Manager(STANDALONE);
14+
15+
$bulk = new MongoDB\Driver\BulkWrite;
16+
$bulk->insert(['x' => 1]);
17+
18+
$manager->executeBulkWrite(NS, $bulk, [
19+
'session' => $manager->startSession(),
20+
'writeConcern' => new MongoDB\Driver\WriteConcern(0),
21+
]);
22+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
23+
24+
echo throws(function() {
25+
$manager = new MongoDB\Driver\Manager(STANDALONE, ['w' => 0]);
26+
27+
$bulk = new MongoDB\Driver\BulkWrite;
28+
$bulk->insert(['x' => 1]);
29+
30+
$manager->executeBulkWrite(NS, $bulk, [
31+
'session' => $manager->startSession(),
32+
]);
33+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
34+
35+
?>
36+
===DONE===
37+
<?php exit(0); ?>
38+
--EXPECT--
39+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
40+
Cannot combine "session" option with an unacknowledged write concern
41+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
42+
Cannot combine "session" option with an unacknowledged write concern
43+
===DONE===
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
MongoDB\Driver\Manager::executeCommand() cannot combine session with unacknowledged write concern
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php NEEDS_CRYPTO(); ?>
6+
<?php NEEDS('STANDALONE'); ?>
7+
<?php NEEDS_ATLEAST_MONGODB_VERSION(STANDALONE, "3.6"); ?>
8+
--FILE--
9+
<?php
10+
require_once __DIR__ . "/../utils/basic.inc";
11+
echo throws(function() {
12+
$manager = new MongoDB\Driver\Manager(STANDALONE);
13+
$command = new MongoDB\Driver\Command([
14+
'insert' => COLLECTION_NAME,
15+
'documents' => [['x' => 1]],
16+
]);
17+
$manager->executeCommand(DATABASE_NAME, $command, [
18+
'session' => $manager->startSession(),
19+
'writeConcern' => new MongoDB\Driver\WriteConcern(0),
20+
]);
21+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
22+
?>
23+
===DONE===
24+
<?php exit(0); ?>
25+
--EXPECT--
26+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
27+
Cannot combine "session" option with an unacknowledged write concern
28+
===DONE===
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
MongoDB\Driver\Manager::executeReadWriteCommand() cannot combine session with unacknowledged write concern
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php NEEDS_CRYPTO(); ?>
6+
<?php NEEDS('STANDALONE'); ?>
7+
<?php NEEDS_ATLEAST_MONGODB_VERSION(STANDALONE, "3.6"); ?>
8+
--FILE--
9+
<?php
10+
require_once __DIR__ . "/../utils/basic.inc";
11+
12+
/* insert should not normally be used with executeReadWriteCommand(), but we are
13+
* only testing executeReadWriteCommand()'s option validation. */
14+
echo throws(function() {
15+
$manager = new MongoDB\Driver\Manager(STANDALONE);
16+
17+
$command = new MongoDB\Driver\Command([
18+
'insert' => COLLECTION_NAME,
19+
'documents' => [['x' => 1]],
20+
]);
21+
22+
$manager->executeReadWriteCommand(DATABASE_NAME, $command, [
23+
'session' => $manager->startSession(),
24+
'writeConcern' => new MongoDB\Driver\WriteConcern(0),
25+
]);
26+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
27+
28+
echo throws(function() {
29+
$manager = new MongoDB\Driver\Manager(STANDALONE, ['w' => 0]);
30+
31+
$command = new MongoDB\Driver\Command([
32+
'insert' => COLLECTION_NAME,
33+
'documents' => [['x' => 1]],
34+
]);
35+
36+
$manager->executeReadWriteCommand(DATABASE_NAME, $command, [
37+
'session' => $manager->startSession(),
38+
]);
39+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
40+
41+
?>
42+
===DONE===
43+
<?php exit(0); ?>
44+
--EXPECT--
45+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
46+
Cannot combine "session" option with an unacknowledged write concern
47+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
48+
Cannot combine "session" option with an unacknowledged write concern
49+
===DONE===
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
MongoDB\Driver\Manager::executeWriteCommand() cannot combine session with unacknowledged write concern
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php NEEDS_CRYPTO(); ?>
6+
<?php NEEDS('STANDALONE'); ?>
7+
<?php NEEDS_ATLEAST_MONGODB_VERSION(STANDALONE, "3.6"); ?>
8+
--FILE--
9+
<?php
10+
require_once __DIR__ . "/../utils/basic.inc";
11+
12+
echo throws(function() {
13+
$manager = new MongoDB\Driver\Manager(STANDALONE);
14+
15+
$command = new MongoDB\Driver\Command([
16+
'insert' => COLLECTION_NAME,
17+
'documents' => [['x' => 1]],
18+
]);
19+
20+
$manager->executeWriteCommand(DATABASE_NAME, $command, [
21+
'session' => $manager->startSession(),
22+
'writeConcern' => new MongoDB\Driver\WriteConcern(0),
23+
]);
24+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
25+
26+
echo throws(function() {
27+
$manager = new MongoDB\Driver\Manager(STANDALONE, ['w' => 0]);
28+
29+
$command = new MongoDB\Driver\Command([
30+
'insert' => COLLECTION_NAME,
31+
'documents' => [['x' => 1]],
32+
]);
33+
34+
$manager->executeWriteCommand(DATABASE_NAME, $command, [
35+
'session' => $manager->startSession(),
36+
]);
37+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
38+
39+
?>
40+
===DONE===
41+
<?php exit(0); ?>
42+
--EXPECT--
43+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
44+
Cannot combine "session" option with an unacknowledged write concern
45+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
46+
Cannot combine "session" option with an unacknowledged write concern
47+
===DONE===

0 commit comments

Comments
 (0)