@@ -73,15 +73,79 @@ static inline bool php_phongo_bulkwrite_update_has_operators(bson_t* bupdate) /*
73
73
return false;
74
74
} /* }}} */
75
75
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
+
76
140
/* Appends a document field for the given opts document and key. Returns true on
77
141
* 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 ) /* {{{ */
79
143
{
80
- zval * value = php_array_fetch (zarr , zarr_key );
144
+ zval * value = php_array_fetch (zarr , key );
81
145
bson_t b = BSON_INITIALIZER ;
82
146
83
147
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 )));
85
149
return false;
86
150
}
87
151
@@ -92,8 +156,8 @@ static bool php_phongo_bulkwrite_opts_append_document(bson_t* opts, const char*
92
156
return false;
93
157
}
94
158
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 );
97
161
bson_destroy (& b );
98
162
return false;
99
163
}
@@ -114,11 +178,18 @@ static bool php_phongo_bulkwrite_opts_append_document(bson_t* opts, const char*
114
178
return false; \
115
179
}
116
180
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
+ } \
122
193
}
123
194
124
195
/* 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
137
208
138
209
PHONGO_BULKWRITE_APPEND_BOOL ("multi" , multi );
139
210
PHONGO_BULKWRITE_APPEND_BOOL ("upsert" , upsert );
140
- PHONGO_BULKWRITE_OPT_DOCUMENT ("arrayFilters" );
211
+ PHONGO_BULKWRITE_OPT_ARRAY ("arrayFilters" );
141
212
PHONGO_BULKWRITE_OPT_DOCUMENT ("collation" );
142
213
143
214
return true;
0 commit comments