* BsonUnwindArray is the internal implementation of $unwind as a set returning function * path -> The path to be unwound * indexFieldName -> optional string to add the index in the output document * preserveNullAndEmpty -> whether to keep null and empty unwind values * * PG_FUNCTION_ARGS contains the document */
| 253 | * PG_FUNCTION_ARGS contains the document |
| 254 | */ |
| 255 | static Datum |
| 256 | BsonUnwindArray(PG_FUNCTION_ARGS, Tuplestorestate *tupleStore, TupleDesc *tupleDescriptor, |
| 257 | char *path, char *indexFieldName, bool |
| 258 | preserveNullAndEmpty) |
| 259 | { |
| 260 | pgbson *document = PG_GETARG_PGBSON_PACKED(0); |
| 261 | |
| 262 | /* Strip the $ prefix from the path */ |
| 263 | if (strlen(path) <= 1) |
| 264 | { |
| 265 | ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg( |
| 266 | "$unwind path should have at least two characters"))); |
| 267 | } |
| 268 | |
| 269 | if (path[0] != '$') |
| 270 | { |
| 271 | ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg( |
| 272 | "$unwind path must be prefixed by $"))); |
| 273 | } |
| 274 | path = path + 1; |
| 275 | |
| 276 | /* Start the iterator at the provided path */ |
| 277 | bson_iter_t documentIterator; |
| 278 | if (!PgbsonInitIteratorAtPath(document, path, &documentIterator)) |
| 279 | { |
| 280 | /* No field was found, return no results on this document */ |
| 281 | if (preserveNullAndEmpty) |
| 282 | { |
| 283 | /* undefined elements are preserved */ |
| 284 | bson_value_t element; |
| 285 | element.value_type = BSON_TYPE_EOD; |
| 286 | Datum values[1]; |
| 287 | bool isNull = false; |
| 288 | |
| 289 | values[0] = PointerGetDatum(BsonUnwindElement(document, |
| 290 | path, |
| 291 | indexFieldName, |
| 292 | -1, |
| 293 | &element)); |
| 294 | tuplestore_putvalues(tupleStore, *tupleDescriptor, values, &isNull); |
| 295 | } |
| 296 | |
| 297 | PG_FREE_IF_COPY(document, 0); |
| 298 | PG_RETURN_VOID(); |
| 299 | } |
| 300 | |
| 301 | if (!BSON_ITER_HOLDS_ARRAY(&documentIterator)) |
| 302 | { |
| 303 | if (!BSON_ITER_HOLDS_NULL(&documentIterator)) |
| 304 | { |
| 305 | /* Single non-null elements are always preserved */ |
| 306 | Datum values[1]; |
| 307 | bool nulls[1]; |
| 308 | |
| 309 | if (indexFieldName == NULL) |
| 310 | { |
| 311 | /* This is just the source doc */ |
| 312 | values[0] = PG_GETARG_DATUM(0); |
no test coverage detected