Hi 4tH-ers!
You haven't heard from me for a long time, that doesn't mean I wasn't working on anything. Reason? I wanted a facility that would update automatically the indexes after a table insert. Well, I got it. Compare this:
OLD
===
begin
refill \ read next CSV record
while
db.clear \ clear the DB buffer
Field> db.buffer -> Rank place
Field> db.buffer -> Name place
Field> db.buffer -> City place
Field> db.buffer -> Country place
Field> db.buffer -> Height_m place
Field> db.buffer -> Height_ft place
Field> db.buffer -> Floors place
Field> db.buffer -> Built place
db.insert \ read fields and insert record
Sky.Name idx.insert drop \ update index, drop flag
Sky.Height idx.insert drop \ update index, drop flag
Sky.City idx.insert drop \ update index, drop flag
Sky.Country idx.insert drop \ update index, drop flag
Sky.Rank idx.insert drop \ update index, drop flag
Sky.Floors idx.insert drop \ update index, drop flag
Sky.Built idx.insert drop \ update index, drop flag
repeat
NEW
===
begin
refill \ read next CSV record
while
db.clear \ clear the DB buffer
Field> db.buffer -> State place
Field> db.buffer -> Abbr place
Field> db.buffer -> Capital place
Field> db.buffer -> Population place
Field> db.buffer -> Area place
Field> db.buffer -> Seats place
dbs.insert \ read fields and insert record
repeat
The only overhead is that you need to declare the indexes once:
US.State US.Abbr US.Capital 3 dbs.indexes abort" Cannot declare indexes"
And if you work neat, you close the database using "dbs.close" instead of "db.close". You'll see all the stuff pop up shortly, just be patient.
I also noticed people have no idea what they can do with the 4tH database library. Note, this thing is about 400 lines of native 4tH, which compiles to 1200 opcodes. Compared to that SQLITE is a giant!
So let's say we have a table with skyscrapers and a table with US states and their capitals and we want to list all skyscrapers in capital cities, like this:
SELECT US.Capital, US.State, Skyscraper.Name, Skyscraper.City
FROM US INNER JOIN Skyscraper ON US.Capital = Skyscraper.City
ORDER BY US.Capital
In 4tH a table consists of 3 elements:
- The table ID;
- The table buffer;
- The table indexes.
All communication goes by the table buffer, keep that in mind. Note we omitted all opening and closing overhead:
US.Capital idx.first \ goto the first record
begin \ ** ENTER THE MAIN LOOP **
US.Capital idx.error 0= \ are we end-of-index?
while
Sky db.use \ switch to the 'Skyscraper' table
UState -> Capital count Sky.City dup idx.clear idx.find
\ find capital using the 'City' index
if \ if we found it
begin \ print fields from both tables
UState -> Capital count type ." , "
UState -> State count type ." , "
Skyscraper -> Name count type ." , "
Skyscraper -> Floors count type cr
Sky.City dup idx.next idx.error 0=
while \ are we end-of-index?
UState -> Capital count Skyscraper -> City count compare
until \ have we had all records
then \ for this capital
US db.use \ switch back to 'US' table
US.Capital dup idx.next idx.error \ get the next capital
until \ are we end-of-index?
\ ** END OF MAIN LOOP **
First we use the "US.Capital" index to fill the "UState" buffer. We use the field "Capital" in the buffer to find the appropriate record in the "Sky.City" index, which in turn fills the "Skyscraper" buffer. We use the flag it returns to determine if we print anything at all - hence an "inner" join. If we used the flag to determine whether to use the contents of a valid "Skyscraper" buffer or to simply print "NULL", it would have been an "outer" join.
The table ID's "Sky" and "US" are used to activate a table (and associated buffers and indexes). As you can see, (de)activation does not invalidate a buffer. Hence, you can still use a valid buffer, even if another table is active.
For those of you who still remember the time of dBase III or Dataflex this should be quite familiar. Sure, it may require a bit more manual work than SQLITE, but that doesn't translate to size. The program doing this query is in total 1300 opcodes - 1200 of them are dedicated to the database engine. On the other hand, you can decide how to approach a query - you don't have to worry about "query optimizers", since you're it. ;-)
Hans Bezemer