<!-- Forthmacs Formatter generated HTML V.2 output -->
<html>
<head>
<title>Forthmacs Database</title>
</head>
<body>
<h1>Forthmacs Database</h1>
<hr>
<p>
This chapter gives a short description about the RISC OS Forthmacs database 
system and includes a glossary of the user interface words.  
<p>
The model sees a database consisting of n <strong>records</strong> , each having 
the same number and sort of <strong>items</strong> .  Both the number of records 
and items have no size limit as long as 
<p>
<p><pre>    record-size = size(item0) + size(item1) + .... + size(lastitem)</pre><p>
<p><pre>    2^31 &gt; record-size * number-of-records</pre><p>
<p>
<p>
The database 'xyz' consists of some files in a directory 
&lt;Forthmacs$Dir&gt;.data.xyz.  The file <strong>data</strong> holds the actual 
records, <strong>struct</strong> defines the database structure, all other files 
called 0 ..  63 are index files.  
<p>
A database definition does two things, it constructs the <strong>data</strong> 
and <strong>struct</strong> files - already existing data files are not 
overwritten -, it also defines forth words in the current vocabulary as a 
programmers user interface.  
<p>
<p>
<h2>Generating a database</h2>
<p>
Let us look at this example: 
<p>
<p><pre>
        &lt;database words
                address         /int
                wordname        /string 31
                vocname         32
        database&gt;
</pre><p>
<p>
First the database name is defined with <code><A href="_smal_BG#7E">&lt;database</A></code> 
words.  A directory <em>&lt;Forthmacs$Dir&gt;.data.words</em> and the data file <em>&lt;Forthmacs$Dir&gt;.data.words.data</em> 
are made if the don't exist already.  
<p>
Also the word <strong>Data:words</strong> is constructed in the current 
vocabulary.  This word would be called a <strong>database descriptor</strong> .  
It is used in all database operations to describe the used database.  It is a 
pointer - plus some more information hidden to the user - pointing to itself if 
the database is <strong>not</strong> open, otherwise it points to an allocated 
data structure describing the database.  
<p>
<p>
<h2>Defining the record structure</h2>
<p>
Now all items within a record are defined.  The first word in a line is the 
items name.  You may later get information about the item, each item has a name, 
a size, possibly a type and an ordinary number as the 5-th item in a record.  
<p>
To make item handling more convenient for the user, there is an <strong>item object</strong> 
created in the current vocabulary called <strong>database:itemname</strong> .  
In our example there would be 3 items: 
<p><pre>  words:address</pre><p>
<p><pre>  words:wordname</pre><p>
<p><pre>  words:vocname</pre><p>
<p>
Each item name is followed by one (or two parameters).  Normally this is a 
decimal number telling the items size in bytes/address units.  Items having just 
a size lack one thing, the database system can <strong>NOT</strong> do any more 
advanced operations on them.  To do indexing for faster sorted access each item 
must also have a type.  
<p>
Currently 3 item types are supported, more might be added easily: 
<p>
<strong>\int</strong> defines a cell wide signed integer 
<p>
<strong>\dint</strong> defines a signed double integer 
<p>
<strong>\string 31 </strong> defines a 'counted string' with 31 characters plus 
count byte 
<p>
<code><A href="_smal_BH#7F">database&gt;</A></code> finishes the database 
declaration.  
<p>
<strong>Implementation restriction:</strong> As RISC OS filenames can't be 
longer than 10 characters, a database can't have a longer name than that.  Don't 
expect upper/lowercase letters to be significant.  Use only characters 
A-Z/a-z/0-9 for database and item names.  
<p>
<p>
<h2>Database operations</h2>
<p>
After defining the database you will want to do some operations on the database.  
First you have to <code><A href="_smal_BI#80">open-database</A></code> before 
you might put some data in it.  The following example will put all words from 
the context dictionary into such a database.  
<p>
Whenever you want to extend the database you have to do <code><A href="_smal_BS#8A">new-records</A>.</code> 
<p>
<p><pre>
: include-current
        Data:words open-database
        astring 0 locals| rec buff |
        context token@ follow
        begin   another?
        while   1 Data:words new-records        \ extend the database by one record
                Data:words records# 1- is rec   \ set the current record#
                \ copy data to buff and set the database items
                dup buff !                      rec buff is words:address
                buff "copy                      rec buff is words:wordname
                context token@ &gt;name buff "copy rec buff is words:vocname
        repeat
        Data:words close-database ;
forth include-current
hidden include-current
</pre><p>
<p>
<strong>include-current</strong> puts all words from the <code><A href="_smal_BB#1C9">current</A></code> 
vocabulary into the database.  The <code><A href="_smal_AA#180">begin</A></code> 
..  <code><A href="_smal_AB#361">while</A></code> ..  <code><A href="_smal_AG#2D6">repeat</A></code> 
loop threads through the vocabulary, for each word found a new record is 
constructed and the items are set.  
<p><pre>  rec buff is words:wordname</pre><p>
puts the data found at buff into the object <strong>words:wordname</strong> 
within record rec.  
<p>
You may use this database to search for an unknown word.  
<p><pre>  : test blword astring "move astring &gt;r searchin words:wordname</pre><p>
<p><pre>         nip r&gt; words:wordname ". ;</pre><p>
<p>
<strong>test swa</strong> will look for the first matching word beginning with <strong>swa</strong> 
in the database.  
<p>
<p>
<h2>Glossary</h2>
<p>

<hr><h3><A name="7E">&lt;database</A></h3> <h5> ( --  ) <kbd> 'name'</kbd> </h5>
<br>
<code><A href="_smal_BG#7E">&lt;database</A></code> name starts the definition 
of a database.  It is followed by pairs of words each defining one <strong>item</strong> 
.  
<p>
<p><pre>  itemname itemsize</pre><p>
<p><pre>  Name 32</pre><p>
<p>
defines an item called Databasename:Name with a size of 32 <code><A href="_smal_BL#1A3">chars</A>.</code> 
<p>
Instead of the decimal number describing the size of an item, there may also be 
one of the following keywords <strong>/int</strong> is a single-cell signed 
integer, <strong>/dint</strong> is a double-cell signed integer, <strong>/string xx</strong> 
is a "counted string" with a size of xx characters plus count byte.  
<p>
<code><A href="_smal_BH#7F">database&gt;</A></code> ends the definition of the 
database.  

<hr><h3><A name="7F">database&gt;</A></h3> <h5> ( --  )</h5>
<br>
ending a database definition 

See: <code><A href="_smal_BG#7E">&lt;database</A></code> 

<hr><h3><A name="80">open-database</A></h3> <h5> ( descriptor --  )</h5>
<br>
The database defined by the descriptor is opened for use.  

See: <code><A href="_smal_BG#7E">&lt;database</A></code> <code><A href="_smal_BJ#81">close-database</A></code> 

<hr><h3><A name="81">close-database</A></h3> <h5> ( descriptor --  )</h5>
<br>
The database defined by the descriptor is closed.  This makes sure, that all 
data and index files are written to disc, the allocated memory is closed and the 
file handlers are closed.  
<p>
It is very important to do this after using a database, as this updates the 
whole <strong>struct</strong> file.  If you don't close the database no corrupt 
files are left, <strong>but</strong> <code><A href="_smal_BS#8A">new-records</A></code> 
are <strong>not</strong> included and valid indexes are <strong>not</strong> 
marked as valid.  
<p>
It would also be possible to do the updating when using the database, but as 
files are used for indexes and the descriptor, it would definitly slow down the 
process.  
<p>

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="82">items#</A></h3> <h5> ( descriptor -- items  )</h5>
<br>
finds the number of items in a database.  The database must be opened before 
use.  

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="83">records#</A></h3> <h5> ( descriptor -- items  )</h5>
<br>
finds the number of records in a database.  The database must be opened before 
use.  

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="84">recsize#</A></h3> <h5> ( descriptor -- items  )</h5>
<br>
finds the size of a record in a database.  The database must be opened before 
use.  

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="85">?find-item</A></h3> <h5> ( str descriptor -- item# true | false  )</h5>
<br>
looks for an item called <strong>str</strong> in the database.  If this is 
found, the items# and <code><A href="_smal_AB#331">true</A></code> are returned, 
otherwise <code><A href="_smal_AM#21C">false</A>.</code> The database must be 
opened before use.  

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="86">index-&gt;record</A></h3> <h5> ( idx item descriptor -- record  )</h5>
<br>
calculates the record number from the index number <strong>idx</strong> in the 
database <strong>descriptor</strong> .  This ensures a valid index file is 
available.  If not, an index file is generated if the item has a supported type 
like <strong>/int</strong> <strong>/dint</strong> or <strong>/string nn</strong> 
.  
<p>
The index generation is rather complex.  It uses a <strong>heap-sort</strong> 
mechanism and works on all database files.  This works in two possible modes 
<p>
1 - the amount of memory available allows the complete database plus indexfile 
to be loaded into memory.  This is &gt;100 times faster than 
<p>
2 - in this mode, all comparing and swapping is done in the file.  This allowes 
BIG databases to be indexed but it is very slow.  
<p>

See: <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="87">get-record</A></h3> <h5> ( record addr descriptor -- addr  )</h5>
<br>
writes the contents of a database record to memory addr 

See: <code><A href="_smal_BQ#88">store-record</A></code> <code><A href="_smal_BR#89">swap-records</A></code> 

<hr><h3><A name="88">store-record</A></h3> <h5> ( record addr descriptor -- addr  )</h5>
<br>
writes the contents at memory addr to a database record 

See: <code><A href="_smal_BP#87">get-record</A></code> <code><A href="_smal_BR#89">swap-records</A></code> 

<hr><h3><A name="89">swap-records</A></h3> <h5> ( record1 record2 descriptor  --  )</h5>
<br>
swaps two record in a database 

See: <code><A href="_smal_BP#87">get-record</A></code> <code><A href="_smal_BQ#88">store-record</A></code> 

<hr><h3><A name="8A">new-records</A></h3> <h5> ( n descriptor --  )</h5>
<br>
creates n empty records in the database 

<hr><h3><A name="8B">get-item</A></h3> <h5> ( record item addr descriptor -- addr  )</h5>
<br>
writes the contents of a database item to memory addr 

See: <code><A href="_smal_BU#8C">store-item</A></code> 

<hr><h3><A name="8C">store-item</A></h3> <h5> ( record item addr descriptor --  )</h5>
<br>
writes the contents at memory addr to a database item 

See: <code><A href="_smal_BT#8B">get-item</A></code> 

<hr><h3><A name="8D">search-item</A></h3> <h5> ( parameter item descriptor -- index record  )</h5>
<br>
Do an indexed search for <strong>parameter</strong> in all items of the 
database.  According to the items type, <strong>parameter</strong> can be an 
integer, a double-integer or a counted string.  

See: <code><A href="_smal_BG#7E">&lt;database</A></code> <code><A href="_smal_BT#8B">get-item</A></code> 
<code><A href="_smal_BO#86">index-&gt;record</A></code> 

<hr><h3><A name="8E">searchin</A></h3> <h5> ( parameter --  ) <kbd> 'item-object'</kbd> </h5>
<br>
This is a method to do a search for parameter on an item object.  The database 
must be open and the item-object must be an indexable type.  

See: <code><A href="_smal_BG#7E">&lt;database</A></code> <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="8F">indexed</A></h3> <h5> ( index -- record  ) <kbd> 'item-object'</kbd> </h5>
<br>
This is a method to calculate the record number from an index on the item 
object.  

See: <code><A href="_smal_BG#7E">&lt;database</A></code> <code><A href="_smal_BI#80">open-database</A></code> 

<hr><h3><A name="90">.database</A></h3> <h5> ( descriptor --  )</h5>
<br>
print some information about the database.  

See: <code><A href="_smal_BI#80">open-database</A></code> 
<p>
<h2>Item Objects</h2>
<p>
In the first part of this chapter the item objects were introduced.  We had 
defined an item object called <em>words:wordname</em> This object has 5 methods 
it can handle 
<p>
Method 1 
<p><pre>  words:wordname ( record addr -- addr )</pre><p>
does a <code><A href="_smal_BT#8B">get-item</A></code> on record and writes it's 
content to addr.  
<p>
Method 2 
<p><pre>  to words:wordname  ( record addr -- )</pre><p>
does a <code><A href="_smal_BU#8C">store-item</A></code> on record and writes 
the content at addr to the item.  
<p>
Method 3 
<p><pre>  addr words:wordname</pre><p>
returns the objects address.  A warning is printed as there is probably no real 
use for this function to the user.  
<p>
Method 4 
<p><pre>  searchin words:wordname ( parameter -- ixd record )</pre><p>
<code><A href="_smal_BW#8E">searchin</A></code> does an indexed search in the 
database for a given parameter.  Returned are both the record and the index 
number.  If the parameter is the same as the found item, index and record are 
always correct, if they don't match, the next higher index is given.  Also note, 
that the database always knows about valid index files, if an index is invalid, 
reindexing is done before search.  If enough memory is available for the whole 
database file and the index, the reindexing is done in RAM which is pretty fast.  
Otherwise all indexing is done in the file, which is <strong>very</strong> slow 
for large databases but allowes databases to be very large principally.  If you 
have a very large database, you might split the database in several files with 
smaller record or you could offer a preindexed database and would use another 
database for user added records.  
<p>
Method 5 
<p><pre>  indexed words:wordname ( index -- record )</pre><p>
<code><A href="_smal_BX#8F">indexed</A></code> calculates the record number from 
an index on the item object.  So you could the phrase: 
<p><pre>  100 0 do i indexed words:wordname here words:wordname ". loop</pre><p>
to list the first 100 alphabetically sorted words in the database.  
<p>
</body>
</html>
