@@ -73,15 +73,79 @@ static inline bool php_phongo_bulkwrite_update_has_operators(bson_t* bupdate) /*
7373 return false;
7474} /* }}} */
7575
76+ /* Returns whether the BSON array's keys are a sequence of integer strings
77+ * starting with "0". BSON_APPEND_ARRAY considers it the caller's responsibility
78+ * to ensure that the array's keys are properly formatted. */
79+ static inline bool php_phongo_bulkwrite_bson_array_has_valid_keys (bson_t * array ) /* {{{ */
80+ {
81+ bson_iter_t iter ;
82+
83+ if (bson_empty (array )) {
84+ return true;
85+ }
86+
87+ if (bson_iter_init (& iter , array )) {
88+ char key [12 ];
89+ int count = 0 ;
90+
91+ while (bson_iter_next (& iter )) {
92+ bson_snprintf (key , sizeof (key ), "%d" , count );
93+
94+ if (0 != strcmp (key , bson_iter_key (& iter ))) {
95+ return false;
96+ }
97+
98+ count ++ ;
99+ }
100+ }
101+
102+ return true;
103+ } /* }}} */
104+
105+ /* Appends an array field for the given opts document and key. Returns true on
106+ * success; otherwise, false is returned and an exception is thrown. */
107+ static bool php_phongo_bulkwrite_opts_append_array (bson_t * opts , const char * key , zval * zarr TSRMLS_DC ) /* {{{ */
108+ {
109+ zval * value = php_array_fetch (zarr , key );
110+ bson_t b = BSON_INITIALIZER ;
111+
112+ if (Z_TYPE_P (value ) != IS_OBJECT && Z_TYPE_P (value ) != IS_ARRAY ) {
113+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"%s\" option to be array or object, %s given" , key , zend_get_type_by_const (Z_TYPE_P (value )));
114+ return false;
115+ }
116+
117+ php_phongo_zval_to_bson (value , PHONGO_BSON_NONE , & b , NULL TSRMLS_CC );
118+
119+ if (EG (exception )) {
120+ bson_destroy (& b );
121+ return false;
122+ }
123+
124+ if (!php_phongo_bulkwrite_bson_array_has_valid_keys (& b )) {
125+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "\"%s\" option has invalid keys for a BSON array" , key );
126+ bson_destroy (& b );
127+ return false;
128+ }
129+
130+ if (!BSON_APPEND_ARRAY (opts , key , & b )) {
131+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error appending \"%s\" option" , key );
132+ bson_destroy (& b );
133+ return false;
134+ }
135+
136+ bson_destroy (& b );
137+ return true;
138+ } /* }}} */
139+
76140/* Appends a document field for the given opts document and key. Returns true on
77141 * success; otherwise, false is returned and an exception is thrown. */
78- static bool php_phongo_bulkwrite_opts_append_document (bson_t * opts , const char * opts_key , zval * zarr , const char * zarr_key TSRMLS_DC ) /* {{{ */
142+ static bool php_phongo_bulkwrite_opts_append_document (bson_t * opts , const char * key , zval * zarr TSRMLS_DC ) /* {{{ */
79143{
80- zval * value = php_array_fetch (zarr , zarr_key );
144+ zval * value = php_array_fetch (zarr , key );
81145 bson_t b = BSON_INITIALIZER ;
82146
83147 if (Z_TYPE_P (value ) != IS_OBJECT && Z_TYPE_P (value ) != IS_ARRAY ) {
84- 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 )));
148+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Expected \"%s\" option to be array or object, %s given" , key , zend_get_type_by_const (Z_TYPE_P (value )));
85149 return false;
86150 }
87151
@@ -92,8 +156,8 @@ static bool php_phongo_bulkwrite_opts_append_document(bson_t* opts, const char*
92156 return false;
93157 }
94158
95- if (!BSON_APPEND_DOCUMENT (opts , opts_key , & b )) {
96- phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error appending \"%s\" option" , opts_key );
159+ if (!BSON_APPEND_DOCUMENT (opts , key , & b )) {
160+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC , "Error appending \"%s\" option" , key );
97161 bson_destroy (& b );
98162 return false;
99163 }
@@ -114,11 +178,18 @@ static bool php_phongo_bulkwrite_opts_append_document(bson_t* opts, const char*
114178 return false; \
115179 }
116180
117- #define PHONGO_BULKWRITE_OPT_DOCUMENT (opt ) \
118- if (zoptions && php_array_existsc(zoptions, (opt))) { \
119- if (!php_phongo_bulkwrite_opts_append_document(boptions, (opt), zoptions, (opt) TSRMLS_CC)) { \
120- return false; \
121- } \
181+ #define PHONGO_BULKWRITE_OPT_ARRAY (opt ) \
182+ if (zoptions && php_array_existsc(zoptions, (opt))) { \
183+ if (!php_phongo_bulkwrite_opts_append_array(boptions, (opt), zoptions TSRMLS_CC)) { \
184+ return false; \
185+ } \
186+ }
187+
188+ #define PHONGO_BULKWRITE_OPT_DOCUMENT (opt ) \
189+ if (zoptions && php_array_existsc(zoptions, (opt))) { \
190+ if (!php_phongo_bulkwrite_opts_append_document(boptions, (opt), zoptions TSRMLS_CC)) { \
191+ return false; \
192+ } \
122193 }
123194
124195/* Applies options (including defaults) for an update operation. */
@@ -137,7 +208,7 @@ static bool php_phongo_bulkwrite_update_apply_options(bson_t* boptions, zval* zo
137208
138209 PHONGO_BULKWRITE_APPEND_BOOL ("multi" , multi );
139210 PHONGO_BULKWRITE_APPEND_BOOL ("upsert" , upsert );
140- PHONGO_BULKWRITE_OPT_DOCUMENT ("arrayFilters" );
211+ PHONGO_BULKWRITE_OPT_ARRAY ("arrayFilters" );
141212 PHONGO_BULKWRITE_OPT_DOCUMENT ("collation" );
142213
143214 return true;
0 commit comments