Execute WITH aggregation path */
| 3627 | |
| 3628 | /* Execute WITH aggregation path */ |
| 3629 | static void execute_with_aggregate(cbm_return_clause_t *wc, binding_t *bindings, int bind_count, |
| 3630 | binding_t **vbindings, int *vcount) { |
| 3631 | int agg_cap = CBM_SZ_256; |
| 3632 | with_agg_t *aggs = calloc(agg_cap, sizeof(with_agg_t)); |
| 3633 | int agg_cnt = 0; |
| 3634 | |
| 3635 | for (int bi = 0; bi < bind_count; bi++) { |
| 3636 | char key[CBM_SZ_1K] = ""; |
| 3637 | with_agg_build_key(wc, &bindings[bi], key, sizeof(key)); |
| 3638 | int found = with_agg_find_or_create(&aggs, &agg_cnt, &agg_cap, wc, &bindings[bi], key); |
| 3639 | with_agg_accumulate(&aggs[found], wc, &bindings[bi]); |
| 3640 | } |
| 3641 | |
| 3642 | *vbindings = safe_realloc(*vbindings, (agg_cnt + SKIP_ONE) * sizeof(binding_t)); |
| 3643 | if (!*vbindings) { |
| 3644 | with_agg_free(aggs, agg_cnt, wc->count); |
| 3645 | return; |
| 3646 | } |
| 3647 | for (int a = 0; a < agg_cnt; a++) { |
| 3648 | binding_t vb = {0}; |
| 3649 | /* Carry the store so node_prop can re-fetch a carried node's properties |
| 3650 | * (and compute in_degree/out_degree) on the projected virtual binding. */ |
| 3651 | vb.store = (bind_count > 0) ? bindings[0].store : NULL; |
| 3652 | for (int ci = 0; ci < wc->count; ci++) { |
| 3653 | char name_buf[CBM_SZ_256]; |
| 3654 | const char *alias = resolve_item_alias(&wc->items[ci], name_buf, sizeof(name_buf)); |
| 3655 | if (wc->items[ci].func) { |
| 3656 | char vbuf[CBM_SZ_64]; |
| 3657 | if (wc->items[ci].distinct && strcmp(wc->items[ci].func, "COUNT") == 0) { |
| 3658 | snprintf(vbuf, sizeof(vbuf), "%d", aggs[a].distinct_n[ci]); /* #239 */ |
| 3659 | } else { |
| 3660 | with_agg_format(wc->items[ci].func, &aggs[a], ci, vbuf, sizeof(vbuf)); |
| 3661 | } |
| 3662 | with_add_vbinding_var(&vb, alias, vbuf); |
| 3663 | } else { |
| 3664 | with_add_vbinding_var(&vb, alias, aggs[a].group_vals[ci]); |
| 3665 | /* Tag the carried virtual var with the node id (when the group |
| 3666 | * var is a node) so node_prop can re-fetch its full properties. */ |
| 3667 | if (aggs[a].group_node_ids[ci] > 0 && vb.var_count > 0) { |
| 3668 | vb.var_nodes[vb.var_count - 1].id = aggs[a].group_node_ids[ci]; |
| 3669 | } |
| 3670 | } |
| 3671 | } |
| 3672 | (*vbindings)[(*vcount)++] = vb; |
| 3673 | } |
| 3674 | with_agg_free(aggs, agg_cnt, wc->count); |
| 3675 | } |
| 3676 | |
| 3677 | /* Execute WITH simple (non-aggregate) projection */ |
| 3678 | static void execute_with_simple(cbm_return_clause_t *wc, binding_t *bindings, int bind_count, |
no test coverage detected