From 43a7e592027d3f4282cdb0314d92c142fca0165a Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Tue, 20 Oct 2026 19:23:03 +0200 Subject: [PATCH] revert(cypher): drop the early-WHERE deferral that #2253 superseded The early WHERE pass in execute_single runs on seed rows where only the first alias is bound, so a NOT on the target node or the relationship pruned every row (#2250). This branch fixed that by skipping the early pass until every alias the WHERE reads was bound. While it waited for review, #2253 (8ab555ee) landed the same fix on main as a three-valued early pass: an unbound alias is UNKNOWN, NOT keeps it UNKNOWN, and only a definite FALSE prunes. This branch's regression tests pass on main's production code unchanged, so restore src/cypher/cypher.c to the branch's base and keep the tests; the merge of main that follows takes main's implementation. Signed-off-by: Martin Vogel --- src/cypher/cypher.c | 52 ++------------------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/src/cypher/cypher.c b/src/cypher/cypher.c index 2a18db7e8..3cc31f9d7 100644 --- a/src/cypher/cypher.c +++ b/src/cypher/cypher.c @@ -4145,54 +4145,7 @@ static void execute_with_simple(cbm_return_clause_t *wc, binding_t *bindings, in } } -static bool condition_bindings_available(const cbm_condition_t *condition, binding_t *binding) { - if (condition->variable && !binding_get(binding, condition->variable) && - !binding_get_edge(binding, condition->variable)) { - return false; - } - for (int i = 0; i < condition->arg_count; i++) { - const char *var = condition->args[i].variable; - if (var && !binding_get(binding, var) && !binding_get_edge(binding, var)) { - return false; - } - } - return true; -} - -static bool expr_bindings_available(const cbm_expr_t *expr, binding_t *binding) { - if (!expr) { - return true; - } - switch (expr->type) { - case EXPR_CONDITION: - return condition_bindings_available(&expr->cond, binding); - case EXPR_AND: - case EXPR_OR: - case EXPR_XOR: - return expr_bindings_available(expr->left, binding) && - expr_bindings_available(expr->right, binding); - case EXPR_NOT: - return expr_bindings_available(expr->left, binding); - } - return false; -} - -static bool where_bindings_available(const cbm_where_clause_t *where, binding_t *binding) { - if (!where) { - return true; - } - if (where->root) { - return expr_bindings_available(where->root, binding); - } - for (int i = 0; i < where->count; i++) { - if (!condition_bindings_available(&where->conditions[i], binding)) { - return false; - } - } - return true; -} - -/* Apply a WHERE filter after its referenced variables have been bound. */ +/* Apply post-WITH WHERE filter */ static void filter_bindings_where(const cbm_where_clause_t *where, binding_t *vbindings, int *vcount) { int kept = 0; @@ -5196,8 +5149,7 @@ static int execute_single(cbm_store_t *store, cbm_query_t *q, const char *projec binding_t b = {0}; b.store = store; binding_set(&b, var_name, &scanned[i]); - bool pass = !q->where || !where_bindings_available(q->where, &b) || - eval_where(q->where, &b); + bool pass = !q->where || eval_where(q->where, &b); if (pass) { bindings[bind_count++] = b; } else {