Skip to content

Commit 7a7b316

Browse files
committed
PHPC-2493: Manager and Server::executeBulkWriteCommand()
1 parent 754a769 commit 7a7b316

12 files changed

+217
-22
lines changed

src/MongoDB/BulkWriteCommand.c

+28-11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,34 @@
3434

3535
zend_class_entry* php_phongo_bulkwritecommand_ce;
3636

37+
/* Creates a mongoc_bulkwriteopts_t from internal options, which should be freed
38+
* by the caller. */
39+
mongoc_bulkwriteopts_t* phongo_bwc_assemble_opts(php_phongo_bulkwritecommand_t* intern)
40+
{
41+
mongoc_bulkwriteopts_t* opts = mongoc_bulkwriteopts_new();
42+
43+
if (intern->bypass != PHONGO_BULKWRITECOMMAND_BYPASS_UNSET) {
44+
mongoc_bulkwriteopts_set_bypassdocumentvalidation(opts, intern->bypass);
45+
}
46+
47+
if (intern->comment) {
48+
mongoc_bulkwriteopts_set_comment(opts, intern->comment);
49+
}
50+
51+
if (intern->let) {
52+
mongoc_bulkwriteopts_set_let(opts, intern->let);
53+
}
54+
55+
mongoc_bulkwriteopts_set_ordered(opts, intern->ordered);
56+
mongoc_bulkwriteopts_set_verboseresults(opts, intern->verbose);
57+
58+
if (intern->write_concern) {
59+
mongoc_bulkwriteopts_set_writeconcern(opts, intern->write_concern);
60+
}
61+
62+
return opts;
63+
}
64+
3765
// TODO: Make this a common utility function to share with BulkWrite.c
3866
/* Extracts the "_id" field of a BSON document into a return value. */
3967
static void phongo_bwc_extract_id(bson_t* doc, zval** return_value)
@@ -381,17 +409,6 @@ static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, deleteOne)
381409
mongoc_bulkwrite_deleteoneopts_destroy(opts);
382410
}
383411

384-
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, execute)
385-
{
386-
php_phongo_bulkwritecommand_t* intern;
387-
388-
intern = Z_BULKWRITECOMMAND_OBJ_P(getThis());
389-
390-
PHONGO_PARSE_PARAMETERS_NONE();
391-
392-
RETURN_LONG(intern->num_ops);
393-
}
394-
395412
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, insertOne)
396413
{
397414
php_phongo_bulkwritecommand_t* intern;

src/MongoDB/BulkWriteCommand.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2024-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef PHONGO_BULKWRITECOMMAND_H
18+
#define PHONGO_BULKWRITECOMMAND_H
19+
20+
#include "mongoc/mongoc.h"
21+
22+
#include "phongo_structs.h"
23+
24+
mongoc_bulkwriteopts_t* phongo_bwc_assemble_opts(php_phongo_bulkwritecommand_t* intern);
25+
26+
#endif /* PHONGO_BULKWRITECOMMAND_H */

src/MongoDB/BulkWriteCommand.stub.php

-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,4 @@ final public function replaceOne(string $namespace, array|object $filter, array|
2525
final public function updateOne(string $namespace, array|object $filter, array|object $update, ?array $options = null): void {}
2626

2727
final public function updateMany(string $namespace, array|object $filter, array|object $update, ?array $options = null): void {}
28-
29-
final public function execute(Manager|Server $managerOrServer): mixed {}
3028
}

src/MongoDB/BulkWriteCommand_arginfo.h

+1-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/MongoDB/Manager.c

+36
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,42 @@ static PHP_METHOD(MongoDB_Driver_Manager, executeBulkWrite)
595595
}
596596
}
597597

598+
/* Executes a BulkWriteCommand (i.e. bulkWrite command for MongoDB 8.0+) */
599+
static PHP_METHOD(MongoDB_Driver_Manager, executeBulkWriteCommand)
600+
{
601+
php_phongo_manager_t* intern;
602+
zval* zbwc;
603+
php_phongo_bulkwritecommand_t* bwc;
604+
zval* zoptions = NULL;
605+
uint32_t server_id = 0;
606+
zval* zsession = NULL;
607+
608+
PHONGO_PARSE_PARAMETERS_START(1, 2)
609+
Z_PARAM_OBJECT_OF_CLASS(zbwc, php_phongo_bulkwritecommand_ce)
610+
Z_PARAM_OPTIONAL
611+
Z_PARAM_ZVAL_OR_NULL(zoptions)
612+
PHONGO_PARSE_PARAMETERS_END();
613+
614+
intern = Z_MANAGER_OBJ_P(getThis());
615+
bwc = Z_BULKWRITECOMMAND_OBJ_P(zbwc);
616+
617+
if (!phongo_parse_session(zoptions, intern->client, NULL, &zsession)) {
618+
/* Exception should already have been thrown */
619+
return;
620+
}
621+
622+
if (!php_phongo_manager_select_server(true, false, NULL, zsession, intern->client, &server_id)) {
623+
/* Exception should already have been thrown */
624+
return;
625+
}
626+
627+
/* If the Server was created in a different process, reset the client so
628+
* that its session pool is cleared. */
629+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern);
630+
631+
phongo_execute_bulkwritecommand(getThis(), bwc, zoptions, server_id, return_value);
632+
}
633+
598634
/* Returns the autoEncryption.encryptedFieldsMap driver option */
599635
static PHP_METHOD(MongoDB_Driver_Manager, getEncryptedFieldsMap)
600636
{

src/MongoDB/Manager.stub.php

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ final public function createClientEncryption(array $options): ClientEncryption {
1818

1919
final public function executeBulkWrite(string $namespace, BulkWrite $bulk, array|WriteConcern|null $options = null): WriteResult {}
2020

21+
final public function executeBulkWriteCommand(BulkWriteCommand $bulkWriteCommand, ?array $options = null): ?BulkWriteCommandResult {}
22+
2123
final public function executeCommand(string $db, Command $command, array|ReadPreference|null $options = null): Cursor {}
2224

2325
final public function executeQuery(string $namespace, Query $query, array|ReadPreference|null $options = null): Cursor {}

src/MongoDB/Manager_arginfo.h

+8-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/MongoDB/Server.c

+24
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,30 @@ static PHP_METHOD(MongoDB_Driver_Server, executeBulkWrite)
215215
}
216216
}
217217

218+
/* Executes a BulkWriteCommand (i.e. bulkWrite command for MongoDB 8.0+) */
219+
static PHP_METHOD(MongoDB_Driver_Server, executeBulkWriteCommand)
220+
{
221+
php_phongo_server_t* intern;
222+
zval* zbwc;
223+
php_phongo_bulkwritecommand_t* bwc;
224+
zval* zoptions = NULL;
225+
226+
PHONGO_PARSE_PARAMETERS_START(1, 2)
227+
Z_PARAM_OBJECT_OF_CLASS(zbwc, php_phongo_bulkwritecommand_ce)
228+
Z_PARAM_OPTIONAL
229+
Z_PARAM_ZVAL_OR_NULL(zoptions)
230+
PHONGO_PARSE_PARAMETERS_END();
231+
232+
intern = Z_SERVER_OBJ_P(getThis());
233+
bwc = Z_BULKWRITECOMMAND_OBJ_P(zbwc);
234+
235+
/* If the Server was created in a different process, reset the client so
236+
* that its session pool is cleared. */
237+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager));
238+
239+
phongo_execute_bulkwritecommand(&intern->manager, bwc, zoptions, intern->server_id, return_value);
240+
}
241+
218242
/* Returns the hostname for this Server */
219243
static PHP_METHOD(MongoDB_Driver_Server, getHost)
220244
{

src/MongoDB/Server.stub.php

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ final private function __construct() {}
7474

7575
final public function executeBulkWrite(string $namespace, BulkWrite $bulkWrite, array|WriteConcern|null $options = null): WriteResult {}
7676

77+
final public function executeBulkWriteCommand(BulkWriteCommand $bulkWriteCommand, ?array $options = null): ?BulkWriteCommandResult {}
78+
7779
final public function executeCommand(string $db, Command $command, array|ReadPreference|null $options = null): Cursor {}
7880

7981
final public function executeQuery(string $namespace, Query $query, array|ReadPreference|null $options = null): Cursor {}

src/MongoDB/Server_arginfo.h

+8-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/phongo_execute.c

+79
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "phongo_execute.h"
2828
#include "phongo_util.h"
2929

30+
#include "MongoDB/BulkWriteCommand.h"
31+
#include "MongoDB/BulkWriteCommandResult.h"
3032
#include "MongoDB/Cursor.h"
3133
#include "MongoDB/ReadPreference.h"
3234
#include "MongoDB/Session.h"
@@ -333,6 +335,83 @@ bool phongo_execute_bulk_write(zval* manager, const char* namespace, php_phongo_
333335
return success;
334336
}
335337

338+
bool phongo_execute_bulkwritecommand(zval* manager, php_phongo_bulkwritecommand_t* bwc, zval* zoptions, uint32_t server_id, zval* return_value)
339+
{
340+
mongoc_client_t* client = NULL;
341+
mongoc_bulkwrite_t* bw = bwc->bw;
342+
mongoc_bulkwriteopts_t* bw_opts = NULL;
343+
mongoc_bulkwritereturn_t bw_ret = { 0 };
344+
php_phongo_bulkwritecommandresult_t* bwcr;
345+
zval* zsession = NULL;
346+
bool success = true;
347+
348+
client = Z_MANAGER_OBJ_P(manager)->client;
349+
350+
if (!phongo_parse_session(zoptions, client, NULL, &zsession)) {
351+
/* Exception should already have been thrown */
352+
return false;
353+
}
354+
355+
mongoc_bulkwrite_set_client(bw, client);
356+
357+
bw_opts = phongo_bwc_assemble_opts(bwc);
358+
mongoc_bulkwriteopts_set_serverid(bw_opts, server_id);
359+
360+
if (zsession) {
361+
mongoc_bulkwrite_set_session(bw, Z_SESSION_OBJ_P(zsession)->client_session);
362+
/* Save a reference to the session on the class struct to avoid leaving
363+
* a dangling pointer within mongoc_bulkwrite_t. */
364+
ZVAL_ZVAL(&bwc->session, zsession, 1, 0);
365+
}
366+
367+
bw_ret = mongoc_bulkwrite_execute(bw, bw_opts);
368+
369+
bwcr = phongo_bulkwritecommandresult_init(return_value, &bw_ret, manager);
370+
371+
if (bw_ret.exc) {
372+
success = false;
373+
bson_error_t error = { 0 };
374+
375+
// Check if there is a top-level error
376+
if (mongoc_bulkwriteexception_error(bw_ret.exc, &error)) {
377+
phongo_throw_exception_from_bson_error_t_and_reply(&error, mongoc_bulkwriteexception_errorreply(bw_ret.exc));
378+
} else {
379+
// TODO: Determine appropriate message w/o top-level error
380+
zend_throw_exception(php_phongo_bulkwritecommandexception_ce, "Bulk write failed", 0);
381+
}
382+
383+
/* Unlike mongoc_bulk_operation_execute, mongoc_bulkwrite_execute may
384+
* report COMMAND_INVALID_ARG alongside a partial result (CDRIVER-5842).
385+
* If there is no result, we can throw InvalidArgumentException without
386+
* proxying it behind a BulkWriteException. */
387+
if (!bw_ret.res && error.domain == MONGOC_ERROR_COMMAND && error.code == MONGOC_ERROR_COMMAND_INVALID_ARG) {
388+
// TODO: Do we care about other mongoc_bulkwriteexception_t fields?
389+
goto cleanup;
390+
}
391+
392+
if (EG(exception)) {
393+
char* message;
394+
395+
(void) spprintf(&message, 0, "Bulk write failed due to previous %s: %s", PHONGO_ZVAL_EXCEPTION_NAME(EG(exception)), error.message);
396+
zend_throw_exception(php_phongo_bulkwritecommandexception_ce, message, 0);
397+
efree(message);
398+
}
399+
400+
/* Ensure error labels are added to the final BulkWriteCommandException. If a
401+
* previous exception was also thrown, error labels will already have
402+
* been added by phongo_throw_exception_from_bson_error_t_and_reply. */
403+
phongo_exception_add_error_labels(mongoc_bulkwriteexception_errorreply(bw_ret.exc));
404+
phongo_add_exception_prop(ZEND_STRL("bulkWriteCommandResult"), return_value);
405+
}
406+
407+
cleanup:
408+
mongoc_bulkwriteopts_destroy(bw_opts);
409+
mongoc_bulkwriteresult_destroy(bw_ret.res);
410+
mongoc_bulkwriteexception_destroy(bw_ret.exc);
411+
412+
return success;
413+
}
414+
336415
bool phongo_execute_command(zval* manager, php_phongo_command_type_t type, const char* db, zval* zcommand, zval* options, uint32_t server_id, zval* return_value)
337416
{
338417
mongoc_client_t* client;

src/phongo_execute.h

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#include <php.h>
2424

25+
#include "phongo_structs.h"
26+
2527
/* This enum is used for processing options and selecting a libmongoc function
2628
* to use in phongo_execute_command. The values are important, as READ and WRITE
2729
* are also used as a bit field to determine whether readPreference,
@@ -37,6 +39,7 @@ typedef enum {
3739
} php_phongo_command_type_t;
3840

3941
bool phongo_execute_bulk_write(zval* manager, const char* namespace, php_phongo_bulkwrite_t* bulk_write, zval* zwriteConcern, uint32_t server_id, zval* return_value);
42+
bool phongo_execute_bulkwritecommand(zval* manager, php_phongo_bulkwritecommand_t* bwc, zval* zoptions, uint32_t server_id, zval* return_value);
4043
bool phongo_execute_command(zval* manager, php_phongo_command_type_t type, const char* db, zval* zcommand, zval* zreadPreference, uint32_t server_id, zval* return_value);
4144
bool phongo_execute_query(zval* manager, const char* namespace, zval* zquery, zval* zreadPreference, uint32_t server_id, zval* return_value);
4245

0 commit comments

Comments
 (0)