Process edges: look up target node, filter by label/props, add binding. * `inbound` controls which end of the edge is the target id. */
| 2853 | /* Process edges: look up target node, filter by label/props, add binding. |
| 2854 | * `inbound` controls which end of the edge is the target id. */ |
| 2855 | static void process_edges(cbm_store_t *store, cbm_edge_t *edges, int edge_count, bool inbound, |
| 2856 | const cbm_node_pattern_t *target_node, binding_t *b, const char *to_var, |
| 2857 | const char *rel_var, binding_t *new_bindings, int *new_count, int max_new, |
| 2858 | int *match_count) { |
| 2859 | /* When the terminal node variable is ALREADY bound (e.g. the second pattern |
| 2860 | * `(c)-[:CALLS]->(f)` where `f` came from an earlier MATCH), we must FILTER |
| 2861 | * to edges that actually reach the bound node — not overwrite the caller's |
| 2862 | * `f` binding with whatever node the edge leads to. Overwriting corrupted |
| 2863 | * the result of dead-code queries and produced wrong rows (#627). */ |
| 2864 | cbm_node_t *bound_to = binding_get(b, to_var); |
| 2865 | int64_t bound_to_id = bound_to ? bound_to->id : 0; |
| 2866 | for (int ei = 0; ei < edge_count && *new_count < max_new; ei++) { |
| 2867 | int64_t tid = inbound ? edges[ei].source_id : edges[ei].target_id; |
| 2868 | if (bound_to && tid != bound_to_id) { |
| 2869 | continue; /* edge does not reach the already-bound terminal node */ |
| 2870 | } |
| 2871 | cbm_node_t found = {0}; |
| 2872 | if (cbm_store_find_node_by_id(store, tid, &found) != CBM_STORE_OK) { |
| 2873 | continue; |
| 2874 | } |
| 2875 | if (target_node->label && !label_alt_matches(found.label, target_node->label)) { |
| 2876 | node_fields_free(&found); |
| 2877 | continue; |
| 2878 | } |
| 2879 | if (!check_inline_props(&found, target_node->props, target_node->prop_count, store)) { |
| 2880 | node_fields_free(&found); |
| 2881 | continue; |
| 2882 | } |
| 2883 | binding_t nb = {0}; |
| 2884 | binding_copy(&nb, b); |
| 2885 | binding_set(&nb, to_var, &found); |
| 2886 | if (rel_var) { |
| 2887 | binding_set_edge(&nb, rel_var, &edges[ei]); |
| 2888 | } |
| 2889 | node_fields_free(&found); |
| 2890 | new_bindings[(*new_count)++] = nb; |
| 2891 | (*match_count)++; |
| 2892 | } |
| 2893 | } |
| 2894 | |
| 2895 | /* Expand variable-length relationship via BFS */ |
| 2896 | static void expand_var_length(cbm_store_t *store, cbm_rel_pattern_t *rel, |
no test coverage detected