retroforth/example/sqlite3/sql.forth
crc f3dd6271bf add example of using sqlite3 via pipes
FossilOrigin-Name: c5afff65edeeeff084caba6726c10369770fea6f5d8cd9676fb6f6e82f808573
2019-05-01 14:02:34 +00:00

64 lines
1.8 KiB
Forth

This is an experimental set of words allowing use of sqlite3
within RETRO.
Do not use this in anything public facing. It doesn't do any
error checking, input validation, or make any attempt to be
remotely secure. It's also slow due to its design.
A lot of work is needed for this to actually be useful outside
of my tests.
This works by opening pipes to sqlite3, capturing the output,
and then processing it from within RETRO. This is slow, but
allows me to not need to deal with adding an FFI, and is
adaptable to similar external tools.
~~~
{{
'Database var
:setup here buffer:set ;
:pipe @Database 'sqlite3_%s_'%s' s:format file:R unix:popen ;
---reveal---
:sql:set-database s:keep !Database ;
:sql:query
[ setup pipe [ dup file:read dup buffer:add n:-zero? ] while unix:pclose ] buffer:preserve here ASCII:LF s:tokenize dup v:dec ;
:sql:split-line (s-a) $| s:tokenize ;
}}
~~~
# Construct an SQL Statement
~~~
{{
{ 'Action 'Choice 'Table 'Clause } [ var ] a:for-each
:clear { &Action &Choice &Table &Clause } [ v:off ] a:for-each ;
---reveal---
:SELECT 'SELECT !Action !Choice ;
:DROP 'DROP !Action ;
:FROM !Table ;
:WHERE !Clause ;
:sql:statement (q-s)
clear call @Clause n:-zero?
[ @Clause @Table @Choice @Action '%s_%s_FROM_%s_WHERE_%s ]
[ @Table @Choice @Action '%s_%s_FROM_%s ] choose
s:format ;
}}
~~~
# Generate Accessor Words
~~~
{{
'Table var
:set-table (s-s) dup s:keep !Table ;
:get-columns (s-a) 'PRAGMA_table\_info("%s") s:format sql:query ;
:id (a-n) #0 a:th fetch s:to-number ;
:column (a-s) #1 a:th fetch @Table '%s:%s s:format ;
:generate (ns-) d:create , [ fetch a:th fetch ] does ;
---reveal---
:sql:accessors-for (s-)
set-table get-columns
[ sql:split-line [ id ] [ column ] bi generate ] a:for-each ;
}}
~~~