diff --git a/src/execution_plan/ops/op_node_by_label_scan.c b/src/execution_plan/ops/op_node_by_label_scan.c index 7604713cce..f89ec67d24 100644 --- a/src/execution_plan/ops/op_node_by_label_scan.c +++ b/src/execution_plan/ops/op_node_by_label_scan.c @@ -112,11 +112,12 @@ static Record NodeByLabelScanConsumeFromChild(OpBase *opBase) { /* depleted will be true in the following cases: * 1. No iterator: GxB_MatrixTupleIter_next will fail and depleted will stay true. This scenario means * that there was no consumption of a record from a child, otherwise there was an iterator. - * 2. Iterator depleted - For every child record the iterator finished the entire matrix scan and it needs to restart. */ - while(depleted) { + * 2. Iterator depleted - For every child record the iterator finished the entire matrix scan and it needs to restart. + * The child record will be NULL if this is the op's first invocation or it has just been reset, in which case we + * should also enter this loop. */ + while(depleted || op->child_record == NULL) { // Try to get a record. if(op->child_record) OpBase_DeleteRecord(op->child_record); - op->child_record = NULL; op->child_record = OpBase_Consume(op->op.children[0]); if(op->child_record == NULL) return NULL; diff --git a/tests/flow/test_path_filter.py b/tests/flow/test_path_filter.py index f724182d49..32a16ee3c8 100644 --- a/tests/flow/test_path_filter.py +++ b/tests/flow/test_path_filter.py @@ -222,3 +222,28 @@ def test10_verify_apply_results(self): # Each source node should be returned exactly once. expected_results = [['a'], ['b']] self.env.assertEquals(result_set.result_set, expected_results) + + def test11_unbound_path_filters(self): + # Build a graph with 2 nodes connected by 1 edge. + node0 = Node(node_id=0, label="L", properties={'x': 'a'}) + node1 = Node(node_id=1, label="L", properties={'x': 'b'}) + edge01 = Edge(src_node=node0, dest_node=node1, relation="R") + redis_graph.add_node(node0) + redis_graph.add_node(node1) + redis_graph.add_edge(edge01) + redis_graph.flush() + + # Emit a query that uses an AntiSemiApply op to return values. + query = "MATCH (n:L) WHERE NOT (:L)-[]->() RETURN n.x ORDER BY n.x" + result_set = redis_graph.query(query) + # The WHERE filter evaluates to false, no results should be returned. + expected_result = [] + self.env.assertEquals(result_set.result_set, expected_result) + + # Emit a query that uses a SemiApply op to return values. + query = "MATCH (n:L) WHERE (:L)-[]->() RETURN n.x ORDER BY n.x" + result_set = redis_graph.query(query) + # The WHERE filter evaluates to true, all results should be returned. + expected_result = [['a'], + ['b']] + self.env.assertEquals(result_set.result_set, expected_result)