JBR - 2011-04-02
I first read about ISBL and PRTV[L1 ](pdf) in early 2008 and it has been running about my thoughts ever since. This is mostly because I find SQL to be unintuitive and difficult to understand. I rather like something more algebraic.
I didn't want to write a complete database engine so here is a package that is a thin layer translating ISBL to sqlite. The main ISBL operators are available. Some features are a little different (delayed evaluation as views). The type system of "Domains" is absent. As with the original ISBL system the database update is problematic but I have provided a nice insert and delete with "+=" and "-=". I'll add update if I get some inspiration.
Here are the pieces:
Some examples to test it:
lappend auto_path /home/john/lib
::tcl::tm::path add .
package require isbl 1
isbl create db data.db
proc ? { 1 2 } { if { $1 ne [string trim $2] } { error "Huh? $1 ne $2" } }
# Table construction
#
db eval { T = % 1->x, 2->y } ; # make some tables from tuples
db eval { T = % 1->x, 4->y } ; # Assignment deletes old data!
db eval { K = % 1->x, 5->l }
db eval { T += % 5->x, 9->y } ; # Insert
db eval { T += % 7->x, 9->y } ; # Insert
db eval { T -= % 7->x } ; # Delete
db eval { X := T % x } ; # isbl reference by name (sql view)
? [db eval X] { 1 5 }
# Relational Operators
#
? [db eval { T }] { 1 4 5 9 } ; # A single table
db eval { T += % 5->x, 9->y } ; # Insert this again - It should replace
db eval { T += % 5->x, 9->y } ; # Insert this again - It should replace
? [db eval { T }] { 1 4 5 9 } ; # Better not have changed
? [db eval { T % x }] { 1 5 } ; # Project
? [db eval { (T + K) % x }] { 1 5 } ; # Union
? [db eval { T % x . K % x }] { 1 } ; # Intersect
? [db eval { T % x - K % x }] { 5 } ; # Difference
? [db eval { T * K }] { 1 4 5 } ; # Join
? [db eval { T : x == 1 }] { 1 4 } ; # Select
? [db eval { T * K % l -> x, x -> f }] { 5 9 1 } ; # Column mapping w/as
? [db eval { T * K % l as x, x as f }] { 5 9 1 } ; # Column mapping w/->
# Special forms
#
db function int mod2 { x } { expr { int($x) % 2 } }
db function { real int } func { x } { list [expr $x*2] 2 }
? [db eval { T : mod2(x) }] { 1 4 5 9 } ; # Select from function return value
? [db eval { T % func(x | a,b) }] { 2 2 10 2 } ; # Project for function w/ tuple return
# Project and remove columns.
#
? [db eval { T % * !x }] { 4 9 }
? [db eval { T % !x }] { 4 9 }
? [db eval { T % y * }] { 4 1 9 5 }
A Makefile to wrap it all up:
PT=/home/john/src/tcllib-1.13/modules/pt/pt
VERSION = 1.0
isbl : main.tcl isbl-$(VERSION).tm
sdx wrap isbl -runtime `which tclkit8.6`
make test
isbl-$(VERSION).tm : unsource isbl.tcl isbl-parser.tcl isbl-actions.tcl
unsource isbl.tcl > isbl-$(VERSION).tm
isbl-actions.tcl : parser-actions isbl-parser.peg isbl-actions.act
parser-actions isbl-parser.peg isbl-actions.act > isbl-actions.tcl
isbl-parser.tcl : isbl-parser.peg
$(PT) generate snit -class isbl-parser -name isbl-parser isbl-parser.tcl peg isbl-parser.
sed -e s/PACKAGE/isbl-parser/ < isbl-parser.tcl > tmp
sed -e s/^return// < tmp > isbl-parser.tcl
rm tmparjen - 2011-04-04 03:09:11
Have you looked at TclRAL? That is a complete relational algebra package
jbr - There was no real imperative to writing the Playing ISBL package other than to explore Parser Tools, sqlite, modules, starpack, and to create an infix relational expression syntax. As a preprocessor for SQL it may be useful in simplifying existing code (or not). TclRAL is excellent. It has a complete set of prefix operators (tcl commands), but it has no backend.