| 4405 | } |
| 4406 | |
| 4407 | static int execute_single(cbm_store_t *store, cbm_query_t *q, const char *project, int max_rows, |
| 4408 | result_builder_t *rb) { |
| 4409 | cbm_pattern_t *pat0 = &q->patterns[0]; |
| 4410 | |
| 4411 | /* Step 1: Scan initial nodes */ |
| 4412 | cbm_node_t *scanned = NULL; |
| 4413 | int scan_count = 0; |
| 4414 | scan_pattern_nodes(store, project, max_rows, &pat0->nodes[0], &scanned, &scan_count); |
| 4415 | |
| 4416 | /* Build initial bindings with early WHERE */ |
| 4417 | int bind_cap = scan_count > max_rows ? scan_count : (max_rows > 0 ? max_rows : SKIP_ONE); |
| 4418 | binding_t *bindings = malloc((bind_cap + SKIP_ONE) * sizeof(binding_t)); |
| 4419 | int bind_count = 0; |
| 4420 | const char *var_name = pat0->nodes[0].variable ? pat0->nodes[0].variable : "_n0"; |
| 4421 | |
| 4422 | for (int i = 0; i < scan_count && bind_count < bind_cap; i++) { |
| 4423 | binding_t b = {0}; |
| 4424 | b.store = store; |
| 4425 | binding_set(&b, var_name, &scanned[i]); |
| 4426 | bool pass = !q->where || eval_where(q->where, &b); |
| 4427 | if (pass) { |
| 4428 | bindings[bind_count++] = b; |
| 4429 | } else { |
| 4430 | binding_free(&b); |
| 4431 | } |
| 4432 | } |
| 4433 | |
| 4434 | /* Step 2: Expand first pattern's relationships */ |
| 4435 | expand_pattern_rels(store, pat0, &bindings, &bind_count, &bind_cap, &var_name, |
| 4436 | q->pattern_optional[0]); |
| 4437 | |
| 4438 | /* Step 2b: Additional patterns */ |
| 4439 | expand_additional_patterns(store, q, project, max_rows, &bindings, &bind_count, &bind_cap); |
| 4440 | |
| 4441 | /* Step 3: Late WHERE */ |
| 4442 | if (q->where && (pat0->rel_count > 0 || q->pattern_count > SKIP_ONE)) { |
| 4443 | filter_bindings_where(q->where, bindings, &bind_count); |
| 4444 | } |
| 4445 | |
| 4446 | /* Step 3b: WITH clause */ |
| 4447 | execute_with_clause(q, &bindings, &bind_count); |
| 4448 | |
| 4449 | /* Step 4: Project results */ |
| 4450 | rb_init(rb); |
| 4451 | if (q->ret) { |
| 4452 | execute_return_clause(q, q->ret, bindings, bind_count, max_rows, rb); |
| 4453 | } else { |
| 4454 | execute_default_projection(pat0, bindings, bind_count, max_rows, rb); |
| 4455 | } |
| 4456 | |
| 4457 | for (int bi = 0; bi < bind_count; bi++) { |
| 4458 | binding_free(&bindings[bi]); |
| 4459 | } |
| 4460 | free(bindings); |
| 4461 | cbm_store_free_nodes(scanned, scan_count); |
| 4462 | return 0; |
| 4463 | } |
| 4464 |
no test coverage detected