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:
parent
f0156c576a
commit
82d04e0649
|
@ -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]
|
||||||
|
|
|
@ -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]))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue