Build advanced WHERE clauses: relationship, entry points, exclude labels. */
| 2558 | |
| 2559 | /* Build advanced WHERE clauses: relationship, entry points, exclude labels. */ |
| 2560 | static void search_where_advanced(const cbm_search_params_t *params, char *where, int where_sz, |
| 2561 | int *wlen, int *nparams, search_bind_t *binds, int *bind_idx) { |
| 2562 | if (params->relationship) { |
| 2563 | char rel_clause[CBM_SZ_256]; |
| 2564 | snprintf(rel_clause, sizeof(rel_clause), |
| 2565 | "EXISTS(SELECT 1 FROM edges e WHERE " |
| 2566 | "(e.source_id = n.id OR e.target_id = n.id) AND e.type = ?%d)", |
| 2567 | *bind_idx + SKIP_ONE); |
| 2568 | *wlen = where_append(where, where_sz, *wlen, nparams, rel_clause); |
| 2569 | where_bind_text(binds, bind_idx, params->relationship); |
| 2570 | } |
| 2571 | if (params->exclude_entry_points) { |
| 2572 | /* Exclude nodes with no inbound CALLS but at least one outbound CALLS. |
| 2573 | * Dead code (degree=0) is NOT excluded — only true entry points. */ |
| 2574 | *wlen = where_append(where, where_sz, *wlen, nparams, |
| 2575 | "NOT (NOT EXISTS(SELECT 1 FROM edges e WHERE e.target_id = n.id " |
| 2576 | "AND e.type = 'CALLS') " |
| 2577 | "AND EXISTS(SELECT 1 FROM edges e2 WHERE e2.source_id = n.id " |
| 2578 | "AND e2.type = 'CALLS'))"); |
| 2579 | } |
| 2580 | if (params->exclude_labels) { |
| 2581 | char excl_clause[CBM_SZ_512]; |
| 2582 | search_build_exclude_labels(params->exclude_labels, binds, bind_idx, excl_clause, |
| 2583 | (int)sizeof(excl_clause)); |
| 2584 | (void)where_append(where, where_sz, *wlen, nparams, excl_clause); |
| 2585 | } |
| 2586 | } |
| 2587 | |
| 2588 | static int search_build_where(const cbm_search_params_t *params, char *where, int where_sz, |
| 2589 | search_bind_t *binds, int *bind_idx, search_like_pool_t *pool) { |
no test coverage detected