@@ -49,6 +49,112 @@ PHONGO_API zend_class_entry *php_phongo_bulkwrite_ce;
49
49
50
50
zend_object_handlers php_phongo_handler_bulkwrite ;
51
51
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
+ /* Appends a document field for the given opts document and key. Returns true on
69
+ * success; otherwise, false is returned and an exception is thrown. */
70
+ static bool php_phongo_bulkwrite_opts_append_document (bson_t * opts , const char * opts_key , zval * zarr , const char * zarr_key TSRMLS_DC )
71
+ {
72
+ zval * value = php_array_fetch (zarr , zarr_key );
73
+ bson_t b = BSON_INITIALIZER ;
74
+
75
+ if (Z_TYPE_P (value ) != IS_OBJECT && Z_TYPE_P (value ) != IS_ARRAY ) {
76
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"%s\" option to be array or object, %s given" , zarr_key , zend_get_type_by_const (Z_TYPE_P (value )));
77
+ return false;
78
+ }
79
+
80
+ phongo_zval_to_bson (value , PHONGO_BSON_NONE , & b , NULL TSRMLS_CC );
81
+
82
+ if (EG (exception )) {
83
+ bson_destroy (& b );
84
+ return false;
85
+ }
86
+
87
+ if (!BSON_APPEND_DOCUMENT (opts , opts_key , & b )) {
88
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error appending \"%s\" option" , opts_key );
89
+ bson_destroy (& b );
90
+ return false;
91
+ }
92
+
93
+ bson_destroy (& b );
94
+ return true;
95
+ }
96
+
97
+ #define PHONGO_BULKWRITE_APPEND_BOOL (opt , value ) \
98
+ if (!BSON_APPEND_BOOL(boptions, (opt), (value))) { \
99
+ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"%s\" option", (opt)); \
100
+ return false; \
101
+ }
102
+
103
+ #define PHONGO_BULKWRITE_APPEND_INT32 (opt , value ) \
104
+ if (!BSON_APPEND_INT32(boptions, (opt), (value))) { \
105
+ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error appending \"%s\" option", (opt)); \
106
+ return false; \
107
+ }
108
+
109
+ #define PHONGO_BULKWRITE_OPT_DOCUMENT (opt ) \
110
+ if (zoptions && php_array_existsc(zoptions, (opt))) { \
111
+ if (!php_phongo_bulkwrite_opts_append_document(boptions, (opt), zoptions, (opt) TSRMLS_CC)) { \
112
+ return false; \
113
+ } \
114
+ }
115
+
116
+ /* Applies options (including defaults) for an update operation. */
117
+ static bool php_phongo_bulkwrite_update_apply_options (bson_t * boptions , zval * zoptions TSRMLS_DC )/* {{{ */
118
+ {
119
+ bool multi = false, upsert = false;
120
+
121
+ if (zoptions ) {
122
+ if (php_array_existsc (zoptions , "multi" )) {
123
+ multi = php_array_fetchc_bool (zoptions , "multi" );
124
+ }
125
+ if (php_array_existsc (zoptions , "upsert" )) {
126
+ upsert = php_array_fetchc_bool (zoptions , "upsert" );
127
+ }
128
+ }
129
+
130
+ PHONGO_BULKWRITE_APPEND_BOOL ("multi" , multi );
131
+ PHONGO_BULKWRITE_APPEND_BOOL ("upsert" , upsert );
132
+ PHONGO_BULKWRITE_OPT_DOCUMENT ("collation" );
133
+
134
+ return true;
135
+ } /* }}} */
136
+
137
+ /* Applies options (including defaults) for an delete operation. */
138
+ static bool php_phongo_bulkwrite_delete_apply_options (bson_t * boptions , zval * zoptions TSRMLS_DC )/* {{{ */
139
+ {
140
+ int32_t limit = 0 ;
141
+
142
+ if (zoptions ) {
143
+ if (php_array_existsc (zoptions , "limit" )) {
144
+ limit = php_array_fetchc_bool (zoptions , "limit" ) ? 1 : 0 ;
145
+ }
146
+ }
147
+
148
+ PHONGO_BULKWRITE_APPEND_INT32 ("limit" , limit );
149
+ PHONGO_BULKWRITE_OPT_DOCUMENT ("collation" );
150
+
151
+ return true;
152
+ } /* }}} */
153
+
154
+ #undef PHONGO_BULKWRITE_APPEND_BOOL
155
+ #undef PHONGO_BULKWRITE_APPEND_INT32
156
+ #undef PHONGO_BULKWRITE_OPT_DOCUMENT
157
+
52
158
/* {{{ proto void BulkWrite::__construct([array $options = array()])
53
159
Constructs a new BulkWrite */
54
160
PHP_METHOD (BulkWrite , __construct )
@@ -135,92 +241,110 @@ PHP_METHOD(BulkWrite, insert)
135
241
Adds an update operation to the BulkWrite */
136
242
PHP_METHOD (BulkWrite , update )
137
243
{
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 ;
244
+ php_phongo_bulkwrite_t * intern ;
245
+ zval * zquery , * zupdate , * zoptions = NULL ;
246
+ bson_t * bquery , * bupdate , * boptions = NULL ;
247
+ bson_error_t error = {0 };
145
248
SUPPRESS_UNUSED_WARNING (return_value_ptr ) SUPPRESS_UNUSED_WARNING (return_value ) SUPPRESS_UNUSED_WARNING (return_value_used )
146
249
147
250
148
251
intern = Z_BULKWRITE_OBJ_P (getThis ());
149
252
150
- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "AA|a!" , & query , & newObj , & updateOptions ) == FAILURE ) {
253
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "AA|a!" , & zquery , & zupdate , & zoptions ) == FAILURE ) {
151
254
return ;
152
255
}
153
256
154
-
155
257
bquery = bson_new ();
156
258
bupdate = bson_new ();
259
+ boptions = bson_new ();
260
+
261
+ phongo_zval_to_bson (zquery , PHONGO_BSON_NONE , bquery , NULL TSRMLS_CC );
157
262
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 );
263
+ if (EG (exception )) {
264
+ goto cleanup ;
265
+ }
266
+
267
+ phongo_zval_to_bson (zupdate , PHONGO_BSON_NONE , bupdate , NULL TSRMLS_CC );
268
+
269
+ if (EG (exception )) {
270
+ goto cleanup ;
271
+ }
160
272
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 ;
273
+ if (!php_phongo_bulkwrite_update_apply_options (boptions , zoptions TSRMLS_CC )) {
274
+ goto cleanup ;
164
275
}
165
276
166
- if (flags & MONGOC_UPDATE_MULTI_UPDATE ) {
167
- mongoc_bulk_operation_update (intern -> bulk , bquery , bupdate , !!(flags & MONGOC_UPDATE_UPSERT ));
277
+ if (php_phongo_bulkwrite_update_has_operators (bupdate )) {
278
+ if (!mongoc_bulk_operation_update_with_opts (intern -> bulk , bquery , bupdate , boptions , & error )) {
279
+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
280
+ goto cleanup ;
281
+ }
168
282
} 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
- }
283
+ if (!bson_validate (bupdate , BSON_VALIDATE_DOT_KEYS |BSON_VALIDATE_DOLLAR_KEYS , NULL )) {
284
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Replacement document may not contain \"$\" or \".\" in keys" );
285
+ goto cleanup ;
286
+ }
287
+
288
+ if (zoptions && php_array_existsc (zoptions , "multi" ) && php_array_fetchc_bool (zoptions , "multi" )) {
289
+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Replacement document conflicts with true \"multi\" option" );
290
+ goto cleanup ;
180
291
}
181
292
182
- if (!replaced ) {
183
- mongoc_bulk_operation_update_one (intern -> bulk , bquery , bupdate , !!(flags & MONGOC_UPDATE_UPSERT ));
293
+ if (!mongoc_bulk_operation_replace_one_with_opts (intern -> bulk , bquery , bupdate , boptions , & error )) {
294
+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
295
+ goto cleanup ;
184
296
}
185
297
}
186
298
187
299
intern -> num_ops ++ ;
188
300
301
+ cleanup :
189
302
bson_clear (& bquery );
190
303
bson_clear (& bupdate );
304
+ bson_clear (& boptions );
191
305
}
192
306
/* }}} */
193
307
194
308
/* {{{ proto void BulkWrite::delete(array|object $query[, array $deleteOptions = array()])
195
309
Adds a delete operation to the BulkWrite */
196
310
PHP_METHOD (BulkWrite , delete )
197
311
{
198
- php_phongo_bulkwrite_t * intern ;
199
- zval * query ;
200
- zval * deleteOptions = NULL ;
201
- bson_t * bson ;
312
+ php_phongo_bulkwrite_t * intern ;
313
+ zval * zquery , * zoptions = NULL ;
314
+ bson_t * bquery , * boptions = NULL ;
315
+ bson_error_t error = { 0 } ;
202
316
SUPPRESS_UNUSED_WARNING (return_value_ptr ) SUPPRESS_UNUSED_WARNING (return_value ) SUPPRESS_UNUSED_WARNING (return_value_used )
203
317
204
318
205
319
intern = Z_BULKWRITE_OBJ_P (getThis ());
206
320
207
- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "A|a!" , & query , & deleteOptions ) == FAILURE ) {
321
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "A|a!" , & zquery , & zoptions ) == FAILURE ) {
208
322
return ;
209
323
}
210
324
325
+ bquery = bson_new ();
326
+ boptions = bson_new ();
327
+
328
+ phongo_zval_to_bson (zquery , PHONGO_BSON_NONE , bquery , NULL TSRMLS_CC );
211
329
212
- bson = bson_new ();
213
- phongo_zval_to_bson (query , PHONGO_BSON_NONE , bson , NULL TSRMLS_CC );
330
+ if (EG (exception )) {
331
+ goto cleanup ;
332
+ }
214
333
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 );
334
+ if (!php_phongo_bulkwrite_delete_apply_options (boptions , zoptions TSRMLS_CC )) {
335
+ goto cleanup ;
336
+ }
337
+
338
+ if (!mongoc_bulk_operation_remove_with_opts (intern -> bulk , bquery , boptions , & error )) {
339
+ phongo_throw_exception_from_bson_error_t (& error TSRMLS_CC );
340
+ goto cleanup ;
219
341
}
220
342
221
343
intern -> num_ops ++ ;
222
344
223
- bson_clear (& bson );
345
+ cleanup :
346
+ bson_clear (& bquery );
347
+ bson_clear (& boptions );
224
348
}
225
349
/* }}} */
226
350
0 commit comments