query: single-pass distinct result extraction (result relation)

ober

0a27e62de04dcd5f6647a6fcffb33cef7f9d41c3

diff --git a/lib/jerboa-db/query/engine.ss b/lib/jerboa-db/query/engine.ss
index 94ed63e..573e5f3 100644
--- a/lib/jerboa-db/query/engine.ss
+++ b/lib/jerboa-db/query/engine.ss
@@ -592,17 +592,21 @@
   ;; Extract result tuples from bindings based on :find specification.
 
   (def (extract-find-results find-vars bindings-list)
-    (let ([has-aggregates? (any-aggregates? find-vars)])
-      (if has-aggregates?
-          (apply-aggregates find-vars bindings-list)
-          (deduplicate-results
-            (map (lambda (bindings)
-                   (map (lambda (var)
-                          (if (logic-var? var)
-                              (binding-ref bindings var)
-                              var))  ;; literal in find
-                        find-vars))
-                 bindings-list)))))
+    (if (any-aggregates? find-vars)
+        (apply-aggregates find-vars bindings-list)
+        ;; Result relation: project each binding to a row and dedup in a single
+        ;; pass into a set, instead of building a full intermediate row list and
+        ;; deduping it separately (one traversal, no intermediate allocation).
+        (let ([seen (make-hashtable equal-hash equal?)] [out '()])
+          (for-each
+            (lambda (b)
+              (let ([row (map (lambda (v) (if (logic-var? v) (binding-ref b v) v))
+                              find-vars)])
+                (unless (hashtable-contains? seen row)
+                  (hashtable-set! seen row #t)
+                  (set! out (cons row out)))))
+            bindings-list)
+          (reverse out))))
 
   (def (any-aggregates? find-vars)
     (exists (lambda (v) (and (pair? v) (aggregate? (car v)))) find-vars))