Skip to content

Commit 1fc30d4

Browse files
committed
PHPC-796: Use flexible opts API for BulkWrite update and delete
1 parent 63f7d31 commit 1fc30d4

File tree

1 file changed

+119
-43
lines changed

1 file changed

+119
-43
lines changed

src/MongoDB/BulkWrite.c

Lines changed: 119 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,74 @@ PHONGO_API zend_class_entry *php_phongo_bulkwrite_ce;
4949

5050
zend_object_handlers php_phongo_handler_bulkwrite;
5151

52+
/* Returns whether any top-level field names in the document contain a "$". */
53+
static inline bool php_phongo_bulkwrite_update_has_operators(bson_t *bupdate) /* {{{ */
54+
{
55+
bson_iter_t iter;
56+
57+
if (bson_iter_init(&iter, bupdate)) {
58+
while (bson_iter_next (&iter)) {
59+
if (strchr(bson_iter_key(&iter), '$')) {
60+
return true;
61+
}
62+
}
63+
}
64+
65+
return false;
66+
} /* }}} */
67+
68+
#define PHONGO_BULKWRITE_APPEND_BOOL(opt, value) \
69+
if (!BSON_APPEND_BOOL(boptions, (opt), (value))) { \
70+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"%s\" option", (opt)); \
71+
return false; \
72+
}
73+
74+
#define PHONGO_BULKWRITE_APPEND_INT32(opt, value) \
75+
if (!BSON_APPEND_INT32(boptions, (opt), (value))) { \
76+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"%s\" option", (opt)); \
77+
return false; \
78+
}
79+
80+
/* Applies options (including defaults) for an update operation. */
81+
static bool php_phongo_bulkwrite_update_apply_options(bson_t *boptions, zval *zoptions TSRMLS_DC)/* {{{ */
82+
{
83+
bool multi = false, upsert = false;
84+
85+
if (zoptions) {
86+
if (php_array_existsc(zoptions, "multi")) {
87+
multi = php_array_fetchc_bool(zoptions, "multi");
88+
}
89+
if (php_array_existsc(zoptions, "upsert")) {
90+
upsert = php_array_fetchc_bool(zoptions, "upsert");
91+
}
92+
}
93+
94+
PHONGO_BULKWRITE_APPEND_BOOL("multi", multi);
95+
PHONGO_BULKWRITE_APPEND_BOOL("upsert", upsert);
96+
97+
return true;
98+
} /* }}} */
99+
100+
/* Applies options (including defaults) for an delete operation. */
101+
static bool php_phongo_bulkwrite_delete_apply_options(bson_t *boptions, zval *zoptions TSRMLS_DC)/* {{{ */
102+
{
103+
int32_t limit = 0;
104+
105+
if (zoptions) {
106+
if (php_array_existsc(zoptions, "limit")) {
107+
limit = php_array_fetchc_bool(zoptions, "limit") ? 1 : 0;
108+
}
109+
}
110+
111+
PHONGO_BULKWRITE_APPEND_INT32("limit", limit);
112+
113+
return true;
114+
} /* }}} */
115+
116+
#undef PHONGO_BULKWRITE_APPEND_BOOL
117+
#undef PHONGO_BULKWRITE_APPEND_INT32
118+
#undef PHONGO_BULKWRITE_OPT_DOCUMENT
119+
52120
/* {{{ proto void BulkWrite::__construct([array $options = array()])
53121
Constructs a new BulkWrite */
54122
PHP_METHOD(BulkWrite, __construct)
@@ -135,92 +203,100 @@ PHP_METHOD(BulkWrite, insert)
135203
Adds an update operation to the BulkWrite */
136204
PHP_METHOD(BulkWrite, update)
137205
{
138-
php_phongo_bulkwrite_t *intern;
139-
zval *query;
140-
zval *newObj;
141-
zval *updateOptions = NULL;
142-
mongoc_update_flags_t flags = MONGOC_UPDATE_NONE;
143-
bson_t *bquery;
144-
bson_t *bupdate;
206+
php_phongo_bulkwrite_t *intern;
207+
zval *zquery, *zupdate, *zoptions = NULL;
208+
bson_t *bquery, *bupdate, *boptions = NULL;
209+
bson_error_t error = {0};
145210
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(return_value) SUPPRESS_UNUSED_WARNING(return_value_used)
146211

147212

148213
intern = Z_BULKWRITE_OBJ_P(getThis());
149214

150-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "AA|a!", &query, &newObj, &updateOptions) == FAILURE) {
215+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "AA|a!", &zquery, &zupdate, &zoptions) == FAILURE) {
151216
return;
152217
}
153218

154-
155219
bquery = bson_new();
156220
bupdate = bson_new();
221+
boptions = bson_new();
157222

158-
phongo_zval_to_bson(query, PHONGO_BSON_NONE, bquery, NULL TSRMLS_CC);
159-
phongo_zval_to_bson(newObj, PHONGO_BSON_NONE, bupdate, NULL TSRMLS_CC);
223+
phongo_zval_to_bson(zquery, PHONGO_BSON_NONE, bquery, NULL TSRMLS_CC);
160224

161-
if (updateOptions) {
162-
flags |= php_array_fetchc_bool(updateOptions, "multi") ? MONGOC_UPDATE_MULTI_UPDATE : 0;
163-
flags |= php_array_fetchc_bool(updateOptions, "upsert") ? MONGOC_UPDATE_UPSERT : 0;
225+
if (EG(exception)) {
226+
goto cleanup;
164227
}
165228

166-
if (flags & MONGOC_UPDATE_MULTI_UPDATE) {
167-
mongoc_bulk_operation_update(intern->bulk, bquery, bupdate, !!(flags & MONGOC_UPDATE_UPSERT));
168-
} else {
169-
bson_iter_t iter;
170-
zend_bool replaced = 0;
171-
172-
if (bson_iter_init(&iter, bupdate)) {
173-
while (bson_iter_next (&iter)) {
174-
if (!strchr (bson_iter_key (&iter), '$')) {
175-
mongoc_bulk_operation_replace_one(intern->bulk, bquery, bupdate, !!(flags & MONGOC_UPDATE_UPSERT));
176-
replaced = 1;
177-
break;
178-
}
179-
}
180-
}
229+
phongo_zval_to_bson(zupdate, PHONGO_BSON_NONE, bupdate, NULL TSRMLS_CC);
230+
231+
if (EG(exception)) {
232+
goto cleanup;
233+
}
234+
235+
if (!php_phongo_bulkwrite_update_apply_options(boptions, zoptions TSRMLS_CC)) {
236+
goto cleanup;
237+
}
181238

182-
if (!replaced) {
183-
mongoc_bulk_operation_update_one(intern->bulk, bquery, bupdate, !!(flags & MONGOC_UPDATE_UPSERT));
239+
if (php_phongo_bulkwrite_update_has_operators(bupdate)) {
240+
if (!mongoc_bulk_operation_update_with_opts(intern->bulk, bquery, bupdate, boptions, &error)) {
241+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
242+
goto cleanup;
243+
}
244+
} else {
245+
if (!mongoc_bulk_operation_replace_one_with_opts(intern->bulk, bquery, bupdate, boptions, &error)) {
246+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
247+
goto cleanup;
184248
}
185249
}
186250

187251
intern->num_ops++;
188252

253+
cleanup:
189254
bson_clear(&bquery);
190255
bson_clear(&bupdate);
256+
bson_clear(&boptions);
191257
}
192258
/* }}} */
193259

194260
/* {{{ proto void BulkWrite::delete(array|object $query[, array $deleteOptions = array()])
195261
Adds a delete operation to the BulkWrite */
196262
PHP_METHOD(BulkWrite, delete)
197263
{
198-
php_phongo_bulkwrite_t *intern;
199-
zval *query;
200-
zval *deleteOptions = NULL;
201-
bson_t *bson;
264+
php_phongo_bulkwrite_t *intern;
265+
zval *zquery, *zoptions = NULL;
266+
bson_t *bquery, *boptions = NULL;
267+
bson_error_t error = {0};
202268
SUPPRESS_UNUSED_WARNING(return_value_ptr) SUPPRESS_UNUSED_WARNING(return_value) SUPPRESS_UNUSED_WARNING(return_value_used)
203269

204270

205271
intern = Z_BULKWRITE_OBJ_P(getThis());
206272

207-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "A|a!", &query, &deleteOptions) == FAILURE) {
273+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "A|a!", &zquery, &zoptions) == FAILURE) {
208274
return;
209275
}
210276

277+
bquery = bson_new();
278+
boptions = bson_new();
211279

212-
bson = bson_new();
213-
phongo_zval_to_bson(query, PHONGO_BSON_NONE, bson, NULL TSRMLS_CC);
280+
phongo_zval_to_bson(zquery, PHONGO_BSON_NONE, bquery, NULL TSRMLS_CC);
214281

215-
if (deleteOptions && php_array_fetchc_bool(deleteOptions, "limit")) {
216-
mongoc_bulk_operation_remove_one(intern->bulk, bson);
217-
} else {
218-
mongoc_bulk_operation_remove(intern->bulk, bson);
282+
if (EG(exception)) {
283+
goto cleanup;
284+
}
285+
286+
if (!php_phongo_bulkwrite_delete_apply_options(boptions, zoptions TSRMLS_CC)) {
287+
goto cleanup;
288+
}
289+
290+
if (!mongoc_bulk_operation_remove_with_opts(intern->bulk, bquery, boptions, &error)) {
291+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
292+
goto cleanup;
219293
}
220294

221295
intern->num_ops++;
222296

223-
bson_clear(&bson);
297+
cleanup:
298+
bson_clear(&bquery);
299+
bson_clear(&boptions);
224300
}
225301
/* }}} */
226302

0 commit comments

Comments
 (0)