From 96f66d3596865f14da065be03779501a6766465a Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 10:41:36 +0000 Subject: [PATCH] datalog: dl-magic-query handles mixed EDB+IDB relations (225/225) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: dl-magic-query was skipping EDB facts for relations that had rules ("rule-headed"). When a single relation has both EDB facts and rules deriving more (mixed EDB+IDB), the rewritten run would miss the EDB portion entirely, producing too few or zero results. Fix: copy ALL existing facts to the internal mdb regardless of whether the relation has rules. EDB-only relations bring their tuples; mixed relations bring both EDB and any pre-saturated IDB (which the rewritten rules would re-derive anyway). 1 new test: link relation seeded with 3 EDB tuples plus a recursive rule via via/2. dl-magic-query rooted at `a` returns 2 results (a→b direct, a→c via via(a,e), link(e,c)). --- lib/datalog/magic.sx | 15 +++++++++------ lib/datalog/scoreboard.json | 8 ++++---- lib/datalog/scoreboard.md | 4 ++-- lib/datalog/tests/magic.sx | 13 +++++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/datalog/magic.sx b/lib/datalog/magic.sx index 4a2953f0..97168a4e 100644 --- a/lib/datalog/magic.sx +++ b/lib/datalog/magic.sx @@ -397,15 +397,18 @@ (mdb (dl-make-db)) (rule-heads (dl-magic-rule-heads rules))) (do - ;; Copy EDB facts (relations not headed by any caller rule). + ;; Copy ALL existing facts. EDB-only relations bring their + ;; tuples; mixed EDB+IDB relations bring both their EDB + ;; portion and any pre-saturated IDB tuples (which the + ;; rewritten rules would re-derive anyway). Skipping facts + ;; for rule-headed relations would leave the magic run + ;; without the EDB portion of mixed relations. (for-each (fn (rel) - (when - (not (dl-member-string? rel rule-heads)) - (for-each - (fn (t) (dl-add-fact! mdb t)) - (dl-rel-tuples db rel)))) + (for-each + (fn (t) (dl-add-fact! mdb t)) + (dl-rel-tuples db rel))) (keys (get db :facts))) ;; Seed + rewritten rules. (dl-add-fact! mdb (get rewritten :seed)) diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index 9692afe3..a566115b 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 224, + "total_passed": 225, "total_failed": 0, - "total": 224, + "total": 225, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -13,8 +13,8 @@ {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":19,"failed":0,"total":19}, {"name":"api","passed":20,"failed":0,"total":20}, - {"name":"magic","passed":24,"failed":0,"total":24}, + {"name":"magic","passed":25,"failed":0,"total":25}, {"name":"demo","passed":21,"failed":0,"total":21} ], - "generated": "2026-05-08T10:36:02+00:00" + "generated": "2026-05-08T10:40:13+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index 7810f66a..a6d1976d 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**224 / 224 passing** (0 failure(s)). +**225 / 225 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -13,5 +13,5 @@ | negation | 10 | 10 | ok | | aggregates | 19 | 19 | ok | | api | 20 | 20 | ok | -| magic | 24 | 24 | ok | +| magic | 25 | 25 | ok | | demo | 21 | 21 | ok | diff --git a/lib/datalog/tests/magic.sx b/lib/datalog/tests/magic.sx index e9ebefb3..90855cd2 100644 --- a/lib/datalog/tests/magic.sx +++ b/lib/datalog/tests/magic.sx @@ -197,6 +197,19 @@ 6) ;; dl-magic-query: end-to-end driver, doesn't mutate caller's db. + ;; Mixed EDB + IDB: a relation can be both EDB-seeded and + ;; rule-derived. dl-magic-query must include the EDB portion + ;; even though the relation has rules. + (dl-mt-test! "magic mixed EDB+IDB" + (len + (dl-magic-query + (dl-program + "link(a, b). link(c, d). link(e, c). + via(a, e). + link(X, Y) :- via(X, M), link(M, Y).") + (list (quote link) (quote a) (quote X)))) + 2) + ;; dl-magic-query falls back to dl-query for built-in, ;; aggregate, and negation goals (the magic seed would ;; otherwise be non-ground).