Execute WITH aggregation path */
| 3967 | |
| 3968 | /* Execute WITH aggregation path */ |
| 3969 | static void execute_with_aggregate(cbm_return_clause_t *wc, binding_t *bindings, int bind_count, |
| 3970 | binding_t **vbindings, int *vcount) { |
| 3971 | int agg_cap = CBM_SZ_256; |
| 3972 | with_agg_t *aggs = calloc(agg_cap, sizeof(with_agg_t)); |
| 3973 | int agg_cnt = 0; |
| 3974 | |
| 3975 | for (int bi = 0; bi < bind_count; bi++) { |
| 3976 | char key[CBM_SZ_1K] = ""; |
| 3977 | with_agg_build_key(wc, &bindings[bi], key, sizeof(key)); |
| 3978 | int found = with_agg_find_or_create(&aggs, &agg_cnt, &agg_cap, wc, &bindings[bi], key); |
| 3979 | with_agg_accumulate(&aggs[found], wc, &bindings[bi]); |
| 3980 | } |
| 3981 | |
| 3982 | *vbindings = safe_realloc(*vbindings, (agg_cnt + SKIP_ONE) * sizeof(binding_t)); |
| 3983 | if (!*vbindings) { |
| 3984 | with_agg_free(aggs, agg_cnt, wc->count); |
| 3985 | return; |
| 3986 | } |
| 3987 | for (int a = 0; a < agg_cnt; a++) { |
| 3988 | binding_t vb = {0}; |
| 3989 | /* Carry the store so node_prop can re-fetch a carried node's properties |
| 3990 | * (and compute in_degree/out_degree) on the projected virtual binding. */ |
| 3991 | vb.store = (bind_count > 0) ? bindings[0].store : NULL; |
| 3992 | for (int ci = 0; ci < wc->count; ci++) { |
| 3993 | char name_buf[CBM_SZ_256]; |
| 3994 | const char *alias = resolve_item_alias(&wc->items[ci], name_buf, sizeof(name_buf)); |
| 3995 | if (is_aggregate_func(wc->items[ci].func)) { |
| 3996 | char vbuf[CBM_SZ_64]; |
| 3997 | if (wc->items[ci].distinct && strcmp(wc->items[ci].func, "COUNT") == 0) { |
| 3998 | snprintf(vbuf, sizeof(vbuf), "%d", aggs[a].distinct_n[ci]); /* #239 */ |
| 3999 | } else { |
| 4000 | with_agg_format(wc->items[ci].func, &aggs[a], ci, vbuf, sizeof(vbuf)); |
| 4001 | } |
| 4002 | with_add_vbinding_var(&vb, alias, vbuf); |
| 4003 | } else { |
| 4004 | with_add_vbinding_var(&vb, alias, aggs[a].group_vals[ci]); |
| 4005 | /* Tag the carried virtual var with the node id (when the group |
| 4006 | * var is a node) so node_prop can re-fetch its full properties. */ |
| 4007 | if (aggs[a].group_node_ids[ci] > 0 && vb.var_count > 0) { |
| 4008 | vb.var_nodes[vb.var_count - 1].id = aggs[a].group_node_ids[ci]; |
| 4009 | } |
| 4010 | } |
| 4011 | } |
| 4012 | (*vbindings)[(*vcount)++] = vb; |
| 4013 | } |
| 4014 | with_agg_free(aggs, agg_cnt, wc->count); |
| 4015 | } |
| 4016 | |
| 4017 | /* Execute WITH simple (non-aggregate) projection */ |
| 4018 | static void execute_with_simple(cbm_return_clause_t *wc, binding_t *bindings, int bind_count, |
no test coverage detected