comparison support, fix bugs in inference rules

* rule expression generation was miscounting the number of parameters
* allow using arbitrary expressions in the head of a rule
This commit is contained in:
Jeremy Penner 2022-03-27 14:34:50 -04:00
parent f0156c576a
commit 82d04e0649
2 changed files with 19 additions and 15 deletions

View file

@ -12,6 +12,7 @@
(local Object (require :core.object)) (local Object (require :core.object))
(local lume (require :lib.lume)) (local lume (require :lib.lume))
(local util (require :lib.util))
(local Sqlog (Object:extend)) (local Sqlog (Object:extend))
@ -38,6 +39,8 @@
; queries with comparisons ; queries with comparisons
; [p x y] (< x 5) -> SELECT p.c1 AS x, p.c2 AS y FROM p WHERE p.c1 < 5 ; [p x y] (< x 5) -> SELECT p.c1 AS x, p.c2 AS y FROM p WHERE p.c1 < 5
; [p x y] (= x y) -> unnecessary but supported, can be written (p x x)
; [p x y] (= x (+ y 1)) -> unnecessary but supported, can be written (p (+ x 1) x)?
; confusing expressions we probably won't support: ; confusing expressions we probably won't support:
; [p (+ x 1) (* x 2)] -> SELECT p.c1 - 1 AS x FROM p WHERE p.c1 + 1 = p.c2 * 2?? ; [p (+ x 1) (* x 2)] -> SELECT p.c1 - 1 AS x FROM p WHERE p.c1 + 1 = p.c2 * 2??
@ -48,10 +51,8 @@
; is there a way to trick sql into generating x = p.c1 - 1 from p.c1 = x + 1? ; is there a way to trick sql into generating x = p.c1 - 1 from p.c1 = x + 1?
; [p z y] (= z (+ x 1)) ; [p z y] (= z (+ x 1))
; unsupported: inline comparisons, explicit equality checks (use unification instead) ; unsupported: inline comparisons
; [p (< x 5) y] -> SELECT p.c1 AS x, p.c2 AS y FROM p WHERE p.c1 < 5 -- does this make sense? seems hard to read, hard to parse ; [p (< x 5) y] -> SELECT p.c1 AS x, p.c2 AS y FROM p WHERE p.c1 < 5 -- does this make sense? seems hard to read, hard to parse
; [p x y] (= x y) -> unnecessary, can be written (p x x)
; [p x y] (= x (+ y 1)) -> unnecessary, can be written (p (+ x 1) x)?
(fn Sqlog.new [self] (fn Sqlog.new [self]
(set self.tables {}) (set self.tables {})
@ -92,6 +93,7 @@
nil (do (tset analysis.variable-mapping varname expr) nil (do (tset analysis.variable-mapping varname expr)
(table.insert analysis.variables varname)))) (table.insert analysis.variables varname))))
(local comparitors (collect [_ op (ipairs [:< :> :<= :>= := :and :or])] op true))
(fn Sqlog.analyze-literal [self analysis literal] (fn Sqlog.analyze-literal [self analysis literal]
(match literal (match literal
[:literal name params] (let [itable (self:reference-name analysis name)] [:literal name params] (let [itable (self:reference-name analysis name)]
@ -99,9 +101,10 @@
(match value (match value
[:var varname] (self:reference-variable analysis varname [:column itable icolumn]) [:var varname] (self:reference-variable analysis varname [:column itable icolumn])
[:const val] (add-clause analysis [:= [:column itable icolumn] [:const val]]) [:const val] (add-clause analysis [:= [:column itable icolumn] [:const val]])
[op & args] (add-clause analysis [:= [:column itable icolumn] value]) (where [op] (= (. comparitors op) nil)) (add-clause analysis [:= [:column itable icolumn] value])
_ (error (.. "expected var or const, got " (fv value)))))) _ (error (.. "expected var, const, or function, got " (fv value))))))
_ (error (.. "Expected literal but got " (fv literal))))) (where [op] (. comparitors op)) (add-clause analysis literal)
_ (error (.. "Expected literal or comparison but got " (fv literal)))))
(fn new-analysis [?parent] (fn new-analysis [?parent]
{:variables [] {:variables []
@ -122,7 +125,7 @@
_ (.. "c" icolumn))) _ (.. "c" icolumn)))
[:as subexpr name] (.. (self:gen-expr analysis subexpr) " AS " name) [:as subexpr name] (.. (self:gen-expr analysis subexpr) " AS " name)
(where [:var name] (. analysis.variable-mapping name)) (self:gen-expr analysis (. analysis.variable-mapping name)) (where [:var name] (. analysis.variable-mapping name)) (self:gen-expr analysis (. analysis.variable-mapping name))
(where [op lhs rhs] (. infix-ops op)) (.. (self:gen-expr analysis lhs) " " op " " (self:gen-expr analysis rhs)) (where [op lhs rhs] (. infix-ops op)) (.. "(" (self:gen-expr analysis lhs) " " op " " (self:gen-expr analysis rhs) ")")
_ (error (.. "Unrecognized expression " (fv expr))))) _ (error (.. "Unrecognized expression " (fv expr)))))
(fn cat [list sep ?f] (fn cat [list sep ?f]
@ -133,17 +136,16 @@
(each [_ literal (ipairs literals)] (self:analyze-literal analysis literal)) (each [_ literal (ipairs literals)] (self:analyze-literal analysis literal))
(match head (match head
[:literal name params] [:literal name params]
(set analysis.selection (icollect [icolumn param (ipairs params)] (set analysis.selection (icollect [icolumn param (ipairs params)] [:as param (.. :c icolumn)]))
(match param
[:var varname] [:as (. analysis.variable-mapping varname) (.. "c" icolumn)]
[:const val] [:as param (.. "c" icolumn)]
_ (error (.. "Expected const or var, got " (fv param))))))
_ (error (.. "Expected literal, got " (fv head)))) _ (error (.. "Expected literal, got " (fv head))))
(self:gen-select analysis))) (self:gen-select analysis)))
(fn Sqlog.gen-rule [self analysis name] (fn Sqlog.gen-rule [self analysis name]
(let [rule (. self.rules name)] (let [rule (. self.rules name)
(.. name "(" (cat rule ", " #(.. "c" $2)) ") AS NOT MATERIALIZED (" column-count (match rule
[[[:literal _ clauses]]] (length clauses)
_ (error (.. "Rule should be list of list of literals, was " (fv rule))))]
(.. name "(" (table.concat (icollect [i (util.countiter column-count)] (.. "c" i)) ", ") ") AS NOT MATERIALIZED ("
(cat rule " UNION " #(self:gen-rule-clause analysis $1)) ")"))) (cat rule " UNION " #(self:gen-rule-clause analysis $1)) ")")))
(fn Sqlog.gen-with-rules [self analysis] (fn Sqlog.gen-with-rules [self analysis]

View file

@ -6,7 +6,9 @@
(s:deftable :p :x :y) (s:deftable :p :x :y)
(s:deftable :q :z) (s:deftable :q :z)
(defrules s (defrules s
([generation name (|| name " jr") 2] [parent name (|| name " jr")])
([generation name (|| name " iii") 3] [ancestor name (|| name " iii")])
([ancestor x y] [parent x y]) ([ancestor x y] [parent x y])
([ancestor x y] [parent x z] [ancestor z y])) ([ancestor x y] [parent x z] [ancestor z y]))
(pp (query s [p x y] [q (+ x 1)])) (pp (query s [generation "bob" descendant nth]))