* Aggregation pipleine stage handler for `$densify`. * Converts to a window function which densifies the incoming documents based on the mode inline * which are later unwinded using bson_lookup_unwind. * * The query returned is of the form: * if densify_spec is: * {"partitionByFields": ["a"], "field": "b", "range": {"bounds": [10, 15], "step": 1 }} * SELECT bson_lookup_unwind(stage2.doc
| 486 | * for this we use a non window function `bson_densify_range_emptytable` |
| 487 | */ |
| 488 | Query * |
| 489 | HandleDensify(const bson_value_t *existingValue, Query *query, |
| 490 | AggregationPipelineBuildContext *context) |
| 491 | { |
| 492 | ReportFeatureUsage(FEATURE_STAGE_DENSIFY); |
| 493 | |
| 494 | if (existingValue->value_type != BSON_TYPE_DOCUMENT) |
| 495 | { |
| 496 | ereport(ERROR, (errcode(ERRCODE_DOCUMENTDB_FAILEDTOPARSE), |
| 497 | errmsg( |
| 498 | "The $densify stage specification must be provided as an object, but encountered %s instead", |
| 499 | BsonTypeName(existingValue->value_type)), |
| 500 | errdetail_log( |
| 501 | "The $densify stage specification must be provided as an object, but encountered %s instead", |
| 502 | BsonTypeName(existingValue->value_type)))); |
| 503 | } |
| 504 | |
| 505 | RangeTblEntry *rte = linitial(query->rtable); |
| 506 | |
| 507 | bool isCollectionDataTable = rte->rtekind == RTE_RELATION; |
| 508 | |
| 509 | pgbson *densifySpec = PgbsonInitFromDocumentBsonValue(existingValue); |
| 510 | Const *densifySpecConst = MakeBsonConst(densifySpec); |
| 511 | |
| 512 | DensifyArguments arguments; |
| 513 | memset(&arguments, 0, sizeof(DensifyArguments)); |
| 514 | PopulateDensifyArgs(&arguments, densifySpec); |
| 515 | |
| 516 | /* |
| 517 | * Special case for range mode densify. |
| 518 | * Generate documents in the range even when the collection is |
| 519 | * - Non existing. |
| 520 | * - Empty collection. |
| 521 | * - Filtered documents are 0. |
| 522 | * |
| 523 | * Convert base query to ... UNION ALL SELECT NULL, to add a NULL row |
| 524 | * at the end which will help generate the docs in the range. |
| 525 | * |
| 526 | * This is done due to the fact that projectors are not called |
| 527 | * if there are no rows. |
| 528 | */ |
| 529 | if (arguments.densifyType == DENSIFY_TYPE_RANGE) |
| 530 | { |
| 531 | query = GenerateUnionAllWithSelectNullQuery(query, context); |
| 532 | |
| 533 | /* We create union all query now its not a data table alone anymore */ |
| 534 | isCollectionDataTable = false; |
| 535 | } |
| 536 | |
| 537 | if (!isCollectionDataTable) |
| 538 | { |
| 539 | query = MigrateQueryToSubQuery(query, context); |
| 540 | } |
| 541 | |
| 542 | TargetEntry *firstEntry = linitial(query->targetList); |
| 543 | Expr *docExpr = (Expr *) firstEntry->expr; |
| 544 | |
| 545 | Expr *partitionByFieldsExpr = NULL; |
nothing calls this directly
no test coverage detected