@database DataBase.guide

@$VER: DataBase V1.12 - by Andrea Galimberti - (C)Amiga Foundation Classes

This guide file has been created using AutoGuide 1.20 - By Fabio Rotondo (fsoft@intercom.it).

@node main "AMIGA-E Modules: Database / Main"


              ** Database V1.02 - Original By Andrea Galimberti **

                       Part of Amiga Foundation Classes




    @{" Introduction " LINK database_intro}   @{" Author(s) Info " LINK database_author}   @{" History " LINK database_history}   @{" AFC doc " LINK "AFC.guide/Main"}


    Requires: @{" nodemaster() " LINK "Nodemaster.guide/Main"}  @{" stringnode() " LINK "Stringnode.guide/Main"}

    Base: $8006

    @{" General concepts " LINK database_general} Fundamental notions on how the engine works

    @{" Database object constructor " LINK database_database}

    The methods of the Database object can be divided into the following
    groups:

          @{" Record related methods " LINK database_record}
          @{" Fields related methods " LINK database_fields}
          @{" Index related methods  " LINK database_index}
          @{" Search results methods " LINK database_search}


    @{" Built-in field types " LINK database_types}


    @{" Error Table " LINK database_errortable}

@endnode

@node database_record "Database / Record related methods"

  These methods lets you add and delete records in a table; move through
the records of a table.

  You access them by appending their name directly after the Database
object name, e.g.:

            table.open()
            table.first()


     NAME                    BRIEF DESCRIPTION
    ------------------------------------------------------------------
    @{" open()                 " LINK database_open} open a table
    @{" create()               " LINK database_create} create a table
    @{" close()                " LINK database_close} close a table
    @{" tablename()            " LINK database_tablename} change name of a table
    @{" add()                  " LINK database_add} add a record
    @{" edit()                 " LINK database_edit} modify current record
    @{" update()               " LINK database_update} write current record contents to file
    @{" delete()               " LINK database_delete} delete current record
    @{" first()                " LINK database_first} move to first record
    @{" succ()                 " LINK database_succ} move to next record
    @{" prev()                 " LINK database_prev} move to previous record
    @{" last()                 " LINK database_last} move to last record
    @{" recordCount()          " LINK database_recordcount} return number of records
    @{" currRec()              " LINK database_currRec} return current record number
    @{" readOnly()             " LINK database_readonly} set/clear the read-only state
    @{" pack()                 " LINK database_pack} physically remove deleted records
    @{" dbftypeadd()           " LINK database_dbftypeadd} link an extra (custom) field type
    @{" locate()               " LINK database_locate} search the records for a list of values
    @{" version()              " LINK database_version} return version of Database class

      
@endnode

@node database_fields "Database / Fields related methods"

  These methods lets you add fields to a table; move through the fields of
a table; read and write the contents of the fields of the current record.

You access these methods through the "fields" property, e.g.:

            table.fields.add()
            table.fields.getv()


     NAME                    BRIEF DESCRIPTION
    ------------------------------------------------------------------
    @{" add()                  " LINK fields_add} add a field to a table
    @{" first()                " LINK fields_first} move to the first field
    @{" succ()                 " LINK fields_succ} move to the next field
    @{" prev()                 " LINK fields_prev} move to the previous field
    @{" last()                 " LINK fields_last} move to the last field
    @{" push()                 " LINK fields_push} store position in the list
    @{" pop()                  " LINK fields_pop} retrieve position in the list
    @{" obj()                  " LINK fields_obj} get pointer to field
    @{" byname()               " LINK fields_byname} move to a field by its name
    @{" getattr()              " LINK fields_getattr} get a field attribute
    @{" setv()                 " LINK fields_setv} set field value
    @{" getv()                 " LINK fields_getv} get field value
    @{" asString()             " LINK fields_asstring} convert field value to string
    @{" assign()               " LINK fields_assign} copy one field to another
    @{" clear()                " LINK fields_clear} clear field list

                              
@endnode

@node database_index "Database / Index related methods"

  These methods lets you add and remove indices in a table; move through
the indices of a table; perform quick searches in a table.

You access these methods through the "index" property, e.g.:

            table.index.add()
            table.index.first()


     NAME                    BRIEF DESCRIPTION
    ------------------------------------------------------------------
    @{" add()                  " LINK index_add} add an index to a table
    @{" first()                " LINK index_first} move to first index in table
    @{" succ()                 " LINK index_succ} move to next index
    @{" prev()                 " LINK index_prev} move to previous index
    @{" last()                 " LINK index_last} move to last index
    @{" del()                  " LINK index_del} delete current index
    @{" clear()                " LINK index_clear} delete all indexes
    @{" byname()               " LINK index_byname} move to an index by its name
    @{" name()                 " LINK index_name} return current index name
    @{" type()                 " LINK index_type} return current index type

                     
@endnode

@node database_search "Database / Search results methods"

  These methods lets you  move through the records that are a result of a
previous @{"locate()" LINK database_locate} call. The records found by the locate() method will be
available until a new locate() is issued.

You access these methods through the "search" property, e.g.:

            table.search.first()
            table.search.succ()


     NAME                    BRIEF DESCRIPTION
    ------------------------------------------------------------------
    @{" first()                " LINK search_first} move to first record found
    @{" succ()                 " LINK search_succ} move to next record found
    @{" prev()                 " LINK search_prev} move to previous record found
    @{" last()                 " LINK search_last} move to last record found
    @{" numitems()             " LINK search_numitems} number of records found

                        
@endnode

@node database_types "Database / Built-in field types"

  The built in field types are the following:


      @{" DBFIELD_STRING  " LINK type_string}       string
      @{" DBFIELD_FLOAT   " LINK type_float}       IEEE single float number
      @{" DBFIELD_INTEGER " LINK type_integer}       integer number
      @{" DBFIELD_BOOLEAN " LINK type_boolean}       boolean value
      @{" DBFIELD_MEMO    " LINK type_memo}       memo


  Note: in the description of the single field type, the expression "all
methods available" means that this field type supports all the methods you
can access through the @{"fields" LINK database_fields} property of the Database object.
Additional methods will be explicitly described.

@endnode

@node database_general "Database fundamental concepts"

  The Database engine has been created exploiting OO programming concepts
at their maximum.
  When you @{"add" LINK fields_add} a field to a table, you are actually adding a field object:
this object knows how to interact with the Database engine and with the
user (by getting and returning values). Fields object are stored in an
internal list: you can access partially this list using the methods of the
@{"fields" LINK database_fields} property; in particular, you can get the pointer to a field
object with the @{"obj()" LINK fields_obj} method.

  All field types are descendants of the "dbfield" object. In general, all
the functions implemented by a field object are accessible through the
methods of the @{"fields" LINK database_fields} property, but there are exceptional cases in which
a field type makes available some additional (and non-standard) methods.
Immediately arises the problem on how to access them; the solution is: you
first get the pointer to that field object (after having moved to it) and
then use its methods by calling them directly. Note that you are
discouraged to follow this procedure when using standard methods: in this
case you must access them through the "fields" property.
  By the way: when a method description says "returns a pointer to a
dbfield object" it actually means that the method returns a pointer to one
of the dbfield descendants, depending on which field type is linked to the
current position of the "fields" list.

  For example, the built-in @{"Memo" LINK type_memo} field type has a property, named "lines",
that allows to manipulate the contents of its lines (and you cannot access
them by other ways than the "lines" property). The steps outlined above are
now:

    1 -   DEF me:PTR TO dbfmemo

    2 -   me:=table.fields.byname('Text')

    3 -   me.lines.add('This is the first line of text')

    ...

  In the above example "table" is the name of your Database object
instance. Note that you have to know the name of the dbfield descendant
(in this case "dbfmemo") because a general pointer to the base-class
"dbfield" doesn't work. The @{"byname" LINK fields_byname} method finds the field object using
its name (I'm not going into deeper detail here, but see this guide for
all the infos you need).


  @{" Steps to create a table          " LINK database_createtable}
  @{" Files belonging to a table       " LINK database_files}
  @{" Extra (non built-in) field types " LINK database_extratypes} <- This is WONDERFUL! :-)

@endnode

@node database_createtable "Database / Steps to create a table"

  To create a table you usually:

  1 -   @{"allocate" LINK database_database} an instance of the Database object passing it the name of
        your table file;

  2 -   @{"add" LINK fields_add} all the fields you need to the table. Note that you can add
        fields only when the table is closed;

  3 -   @{"add" LINK index_add} all the indexes you need to the table;

  4 -   call the @{"create()" LINK database_create} method;

  5 -   from now on the table is open to accept new records;

  6 -   remember to @{"close()" LINK database_close} the table (and END the Database object) before
        exiting.


  You can use the same Database object to create and/or open different
tables; after having closed the currently open table you:

  1 -   change the name of the table file with the @{"tablename()" LINK database_tablename} method;

  2 -   @{"clear" LINK fields_clear} the list of fields (if you need to);

  3 -   @{"clear" LINK index_clear} the list of indexes (if you need to);

  4 -   follow the preceding steps starting from point 2.


  To open an existing table you:

  1 -   change the name of the table while @{"allocating" LINK database_database} the object or with
        the @{"tablename()" LINK database_tablename} method;

  2 -   call the @{"open()" LINK database_open} method

  3 -   from now on the table is open to accept new records.

@endnode

@node database_files "Database / Files belonging to a table"

  A table is composed of the following files:

  table_file       =  table main file, containing all the fixed-length
                      fields

  table_file.data  =  file containing the data belonging to the blob fields
                      (varying-length fields like the Memo field)

  table_file.idx   =  file containing the indexes data


  Obviuosly, except for the main file, the other files are present only if
they are needed: if you have no blob fields the table_file.data file is
absent; similarly if you have no indexes the table_file.idx file is not
written.

@endnode

@node database_extratypes "Database / Extra field types"

  This Database engine allows for third party (non built-in) field types to
be linked to a Database object and used just as the built-in ones.

  Each extra type (as I'm going to call it from now on) is contained in a
#?.m file. Its documentation must tell you:

  1 -   the identification name of the type (e.g., DBFIELD_STRING)

  2 -   the name of the object (e.g., dbfstring)

  3 -   what it is used for (!)

  4 -   extra methods you can access directly by using a pointer to the
        field (as explained in the @{"previous section" LINK database_general})

  5 -   extra tags accepted when adding a field with the @{"fields.add()" LINK fields_add}
        method

  The extra type may not support all the standard methods accessible
through the @{"fields" LINK database_fields} property.

  Before using an extra type you first allocate an instance of the Database
object (if you haven't already done it) and then link the extra type using
the @{"dbftypeadd()" LINK database_dbftypeadd} method. Then you can add a field OF this extra type just
as you add all the other fields (with the use of the @{"fields.add()" LINK fields_add} method).
  If you try to @{"open()" LINK database_open} a table that contains extra types before linking
that types to your Database object, it will be Raised the
@{"DBASE_ERR_UNKNOWNFIELDTYPE" LINK database_errortable} exception.

@endnode

@node database_author "Author(s) Info"

    Original By:  Andrea Galimberti

    E Version By: Andrea Galimberti

@endnode

@node database_intro "Database / Introduction"

  Database engine
  ===============

  The Database object makes possible to create and easily manage tables.
The concepts at the base of this engine are similar to those found in other
database engines: a table is made of fields; you have to specify name, type
and dimension of every field of your table; fields are usually of fixed
length, but are also allowed blob fields ("blob" stands for "Binary Large
OBject") like the Memo field or a graphic field; you can perform quick
searches in the table using the indexed fields.

  This Database engine offers you:

  * built-in field types: string, float, integer, boolean and memo

  * blob fields (e.g., the built-in memo field type)

  * custom (external) field types can be recognized by this engine and used
    just like the built-in ones

  * indexes can be added to fields

  * locate() method to find records matching some search criteria; locate()
    exploits indexes to speed up the search process

  * lots of methods to move through records and fields ("first", "succ",
    "byname", and so on...)

  * assign() method to perform fast copies of a field contents to another
    field of the same type (it works also with blob fields)

  * buffered I/O to the files

  The Database object puts at your fingertips functions to move through the
records of your table, or to move through the contents of the fields of a
record, e.g.: to load the next record of a table you simply say "succ"; to
find a field by its name you call the "byname" function, and so on...

  The built-in field types are: string, float, integer, boolean and memo.
But the Database object is not limited to these types. In fact the most
astonishing feature of this Database engine is the capability of managing
custom fields: that is to say, everyone can build a strange type of field
(following the instructions contained in another guide), not included in
the standard built-in ones, and can link it to this engine. From now on the
Database object is able to treat this new field just as it treats the
built-in ones!

@endnode

@node database_errortable "Database / Error Table"

 Val  | Name                         | Description
------+------------------------------+---------------------------------
      |                              |
 0000 | DBASE_ERR_NOMEM              | No memory
 0001 | DBASE_ERR_NOFIELDNAME        | Field has no name
 0002 | DBASE_ERR_NOFIELDS           | Table has no fields
 0003 | DBASE_ERR_INVALIDLENGTH      | Invalid field length
 0004 | DBASE_ERR_IOERR              | I/O Error (use the IoErr() system call for more info)
 0005 | DBASE_ERR_TABLECLOSED        | Cannot perform this operation on a closed table
 0006 | DBASE_ERR_NOMODE             | Table is not in Add or Edit mode
 0007 | DBASE_ERR_READONLY           | Table is Read Only
 0008 | DBASE_ERR_TABLEOPEN          | Cannot perform this operation on an open table
 0009 | DBASE_ERR_REQUIRED           | Required field missing
 000A | DBASE_ERR_NODATAFILE         | Blob file missing
 000B | DBASE_ERR_NOTABLENAME        | Table name missing
 000C | DBASE_ERR_VERSION            | Wrong table structure version
 000D | DBASE_ERR_NOMATCHFIELD       | Fields do not match
 000E | DBASE_ERR_CLASSEXISTS        | Field class ID already exists
 000F | DBASE_ERR_UNKNOWNFIELDTYPE   | Unknown field type
 0010 | DBASE_ERR_FIELDDOESNTEXIST   | Field doesn't exist
 0011 | DBASE_ERR_INDEXEXISTS        | Index already exists
 0012 | DBASE_ERR_NOINDEXFIELD       | Field cannot be indexed
 0013 | DBASE_ERR_NOAFCD             | Invalid Main file format
 0014 | DBASE_ERR_NOAFCB             | Invalid Blob file format
 0015 | DBASE_ERR_NOAFCI             | Invalid Index file format

@endnode

@node database_history "Database / History"

 Version  - Changes

  1.02  -  ENH: added "mode" parameter to locate() method: now string
                matching can be case insensitive.

  1.01  -  ADD: currRec() method
           FIX: recno update in methods: first(), succ(), prev().

  1.00     - First public release

@endnode

@node type_string "Field type / String"

  ID:             DBFIELD_STRING

  OBJECT NAME:    dbfstring

  CONTENT:        string

  LENGTH (bytes): anything from 1 to 32768

  INDEX:          any

  METHODS:        all methods available

@endnode

@node type_float "Field type / Float"

  ID:             DBFIELD_FLOAT

  OBJECT NAME:    dbffloat

  CONTENT:        IEEE single precision floating point number

  LENGTH (bytes): 4

  INDEX:          any

  METHODS:        all methods available

@endnode

@node type_integer "Field type / Integer"

  ID:             DBFIELD_INTEGER

  OBJECT NAME:    dbfinteger

  CONTENT:        integer number

  LENGTH (bytes): 4

  INDEX:          any

  METHODS:        all methods available

@endnode

@node type_boolean "Field type / Boolean"

  ID:             DBFIELD_BOOLEAN

  OBJECT NAME:    dbfboolean

  CONTENT:        boolean value (TRUE = 255)

  LENGTH (bytes): 1

  INDEX:          any

  METHODS:        all methods available

@endnode

@node type_memo "Field type / Memo"

  ID:             DBFIELD_MEMO

  OBJECT NAME:    dbfmemo

  CONTENT:        list of string values (constituting the memo lines)

  LENGTH (bytes): anything from 1 to 32768
                  The length parameter is applicable because the memo field
                  can also have a fixed length part written in the main
                  table file.

  INDEX:          not available

  METHODS:        all methods available

                  The memo field type has a property called "lines" by
                  means of which one can access its lines. In this case the
                  setv() and getv() standard methods refer to the memo
                  fixed part that is interpreted as a link to an external
                  file containing the lines to be read.


  * Method changes:

  setv(): sets the name of an external file containing the lines to be
          read (in this case lines contained in the current record of the
          table will ignored)

  getv(): gets the name of the external file linked to the memo field.


  * New methods:

  you access new methods by getting the pointer to the memo field (see the
@{"Fundamental concepts section" LINK database_general} for more info) and using its "lines" property
(e.g., "memo.lines.first()").
  The "lines" property is based on a @{"stringnode" LINK "Stringnode.guide/Main"} object, so you can refer to
the stringnode class reference for more info.


     NAME                    BRIEF DESCRIPTION
    ------------------------------------------------------------------
    @{" add()                  " LINK memo_lines_add} add a new line
    @{" first()                " LINK memo_lines_first} move to first line
    @{" succ()                 " LINK memo_lines_succ} move to next line
    @{" prev()                 " LINK memo_lines_prev} move to previous line
    @{" last()                 " LINK memo_lines_last} move to last line
    @{" obj()                  " LINK memo_lines_obj} return current line
    @{" del()                  " LINK memo_lines_del} delete current line
    @{" clear()                " LINK memo_lines_clear} clear all lines
    @{" change()               " LINK memo_lines_change} substitute a text line
    @{" numitems()             " LINK memo_lines_numitems} return number of lines
    @{" sort()                 " LINK memo_lines_sort} sort lines
    @{" search()               " LINK memo_lines_search} search for a string
    @{" load()                 " LINK memo_lines_load} load lines from file
    @{" save()                 " LINK memo_lines_save} save lines to file

      
@endnode

@node memo_lines_add "Memo field / lines.add()"

          NAME: add(string)

   DESCRIPTION: adds a new line of text to the memo field. This method
                allocates its own memory for the text line and copies the
                contents of the string parameter.

        INPUTS: string = string of text to be added

       RESULTS: a pointer to the newly created text line.

      SEE ALSO: @{" del()            " LINK memo_lines_del}
                @{" stringnode.add() " LINK "Stringnode.guide/StringNode_add"}

@endnode

@node memo_lines_del "Memo field / lines.del()"

          NAME: del()

   DESCRIPTION: deletes current text line.

        INPUTS: NONE

       RESULTS: pointer to the next available line of text, or NIL if the
                list is empty.

      SEE ALSO: @{" add()            " LINK memo_lines_add}
                @{" clear()          " LINK memo_lines_clear}
                @{" stringnode.del() " LINK "Stringnode.guide/StringNode_del"}

@endnode

@node memo_lines_clear "Memo field / lines.clear()"

          NAME: clear()

   DESCRIPTION: deletes all lines of text.

        INPUTS: NONE

       RESULTS: NONE

      SEE ALSO: @{" del()              " LINK memo_lines_del}
                @{" stringnode.clear() " LINK "Stringnode.guide/StringNode_clear"}

@endnode

@node memo_lines_change "Memo field / lines.change()"

          NAME: change(string)

   DESCRIPTION: replaces the current text line with the contents of the
                string parameter.

        INPUTS: string = text that will replace the current text line

       RESULTS: pointer to the current text line

      SEE ALSO: @{" add()               " LINK memo_lines_add}
                @{" stringnode.change() " LINK "Stringnode.guide/StringNode_change"}

@endnode

@node memo_lines_sort "Memo field / lines.sort()"

          NAME: sort(nocase=FALSE, inverted=FALSE)

   DESCRIPTION: sorts all the text lines. If you specify TRUE for the
                nocase parameter the sort will be case insensitive; if you
                specify TRUE for the inverted parameter, lines will be
                sorted in a high-to-low order.

        INPUTS: nocase   = TRUE -> sort will be case insensitive
                inverted = TRUE -> sort will be high-to-low

                Note that both the parameters are optional.

       RESULTS: NONE

      SEE ALSO: @{" stringnode.sort() " LINK "Stringnode.guide/StringNode_sort"}

@endnode

@node memo_lines_first "Memo field / lines.first()"

          NAME: first()

   DESCRIPTION: moves to the first line of text.

        INPUTS: NONE

       RESULTS: pointer to the first text line, or NIL if list is empty

      SEE ALSO: @{" succ()             " LINK memo_lines_succ}
                @{" prev()             " LINK memo_lines_prev}
                @{" last()             " LINK memo_lines_last}
                @{" stringnode.first() " LINK "Stringnode.guide/StringNode_first"}

@endnode

@node memo_lines_prev "Memo field / lines.prev()"

          NAME: prev()

   DESCRIPTION: moves to the preceding line of text.

        INPUTS: NONE

       RESULTS: pointer to the preceding text line, or NIL if there are no
                more lines (head of list reached)

      SEE ALSO: @{" succ()            " LINK memo_lines_succ}
                @{" first()           " LINK memo_lines_first}
                @{" last()            " LINK memo_lines_last}
                @{" stringnode.prev() " LINK "Stringnode.guide/StringNode_prev"}

@endnode

@node memo_lines_succ "Memo field / lines.succ()"

          NAME: succ()

   DESCRIPTION: moves to the next line of text.

        INPUTS: NONE

       RESULTS: pointer to the next text line, or NIL if there are no
                more lines (tail of list reached)

      SEE ALSO: @{" prev()            " LINK memo_lines_prev}
                @{" first()           " LINK memo_lines_first}
                @{" last()            " LINK memo_lines_last}
                @{" stringnode.succ() " LINK "Stringnode.guide/StringNode_succ"}

@endnode

@node memo_lines_last "Memo field / lines.last()"

          NAME: last()

   DESCRIPTION: moves to the last line of text.

        INPUTS: NONE

       RESULTS: pointer to the last text line, or NIL if list is empty

      SEE ALSO: @{" succ()            " LINK memo_lines_succ}
                @{" first()           " LINK memo_lines_first}
                @{" prev()            " LINK memo_lines_prev}
                @{" stringnode.last() " LINK "Stringnode.guide/StringNode_last"}

@endnode

@node memo_lines_numitems "Memo field / lines.numitems()"

          NAME: numitems()

   DESCRIPTION: returns the number of text lines.

        INPUTS: NONE

       RESULTS: number of field text lines.

      SEE ALSO: @{" stringnode.numitems() " LINK "Stringnode.guide/StringNode_numitems"}

@endnode

@node memo_lines_obj "Memo field / lines.obj()"

          NAME: obj()

   DESCRIPTION: returns the pointer to the current line of text.

        INPUTS: NONE

       RESULTS: pointer to current text line

      SEE ALSO: @{" stringnode.obj() " LINK "Stringnode.guide/StringNode_obj"}

@endnode

@node memo_lines_search "Memo field / lines.search()"

          NAME: search(string, from_here=FALSE)

   DESCRIPTION: searches through the text lines for a string matching the
                string parameter. The "string" parameter may contain the
                standard AmigaDOS pattern matching characters.
                The optional from_here parameter specifies if the search
                has to begin from the current node or from the first one.

                Note that: 1) search is case insensitive;
                           2) if the search fails the current node won't
                              move, otherwise it'll be positioned on a node
                              matching the search criteria.

        INPUTS: string    = string (or AmigaDOS search pattern) to search for
                from_here = TRUE -> search starts from current node

       RESULTS: pointer to a string if something found, otherwise FALSE

      SEE ALSO: @{" stringnode.search()" LINK "Stringnode.guide/StringNode_search"}

@endnode

@node memo_lines_load "Memo field / lines.load()"

          NAME: load(file_name, max_length=255)

   DESCRIPTION: loads all text lines from the file named "file_name". The
                optional max_length specifies the maximum length of the
                lines that will be loaded: this serves for buffer
                allocating purposes.

                Note that all existing lines will be cleared.

        INPUTS: file_name  = name of file containing the lines to be loaded
                max_length = max length of lines to be loaded.

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_NOMEM   if buffer allocation failed

                DBASE_ERR_IOERR   if something went wrong with the I/O
                                  routines

      SEE ALSO: @{" save() " LINK memo_lines_save}

@endnode

@node memo_lines_save "Memo field / lines.save()"

          NAME: save(file_name)

   DESCRIPTION: saves all text lines to a file named "file_name".

        INPUTS: file_name = name of file where to save the text lines.

       RESULTS: NONE

                This method raises the @{"DBASE_ERR_IOERR" LINK database_errortable} exception if
                something goes wrong with the I/O routines.

      SEE ALSO: @{" load() " LINK memo_lines_load}

@endnode

@node fields_add "Database / fields.add()"

          NAME: add(tag)

   DESCRIPTION: add a field to a table.
                The tag parameter is a NIL-terminated list of tags. This
                method understands the following tags:

                DBFTAG_NAME   = name of the field to be added (must be
                                unique)

                DBFTAG_TYPE   = type of the field; it can be one of the
                                following built-in types:

                                @{"DBFIELD_STRING" LINK type_string}  = string
                                @{"DBFIELD_FLOAT" LINK type_float}   = IEEE single float number
                                @{"DBFIELD_INTEGER" LINK type_integer} = integer number
                                @{"DBFIELD_BOOLEAN" LINK type_boolean} = boolean value
                                @{"DBFIELD_MEMO" LINK type_memo}    = memo

                DBFTAG_LENGTH = length of the field

                DBFTAG_REQUIRED = TRUE if the field must be assigned a
                                  value in every record


  Note that more field types can be added by linking them to the Database
engine using the @{"dbftypeadd()" LINK database_dbftypeadd} procedure, and to these new types you can
pass more tags than the four listed above. If you need specific info about
these extra field classes refer to their documentation.


        INPUTS: tag = NIL-term taglist

       RESULTS: NONE

                You cannot add field definitions if the table is open, so
                in this case the procedure raises the DBASE_ERR_TABLEOPEN
                exception.

                If the value of DBFTAG_TYPE is not included in the list of
                known field types a DBASE_ERR_UNKNOWNFIELDTYPE exception
                will be raised.

      SEE ALSO: @{" clear() " LINK fields_clear}

@endnode

@node fields_first "Database / fields.first()"

          NAME: first()

   DESCRIPTION: moves to the first field of the table

        INPUTS: NONE

       RESULTS: pointer to a dbfield object or NIL if the field list is
                empty

      SEE ALSO: @{" succ() " LINK fields_succ}
                @{" prev() " LINK fields_prev}
                @{" last() " LINK fields_last}

@endnode

@node fields_succ "Database / fields.succ()"

          NAME: succ()

   DESCRIPTION: moves to the next field in the table

        INPUTS: NONE

       RESULTS: pointer to a dbfield object or NIL if there are no more
                fields in the list (tail of list reached)

      SEE ALSO: @{" first() " LINK fields_first}
                @{" prev()  " LINK fields_prev}
                @{" last()  " LINK fields_last}

@endnode

@node fields_prev "Database / fields.prev()"

          NAME: prev()

   DESCRIPTION: moves to the preceding field in the table

        INPUTS: NONE

       RESULTS: pointer to a dbfield object or NIL if there are no more
                fields in the list (head of list reached)

      SEE ALSO: @{" first() " LINK fields_first}
                @{" succ()  " LINK fields_succ}
                @{" last()  " LINK fields_last}

@endnode

@node fields_last "Database / fields.last()"

          NAME: last()

   DESCRIPTION: moves to the last field in the table

        INPUTS: NONE

       RESULTS: pointer to a dbfield object or NIL if the field list is
                empty

      SEE ALSO: @{" first() " LINK fields_first}
                @{" succ()  " LINK fields_succ}
                @{" prev()  " LINK fields_prev}

@endnode

@node fields_push "Database / fields.push()"

          NAME: push()

   DESCRIPTION: stores the current position in the field list on the stack.
                To retrieve such position you call the @{"pop()" LINK fields_pop} method. There
                are 8 push()ing levels available on the stack (that is to
                say you can store up to 8 positions before the stack gets
                full).

                For more info see @{"nodemaster.push()" LINK "Nodemaster.guide/Nodemaster_push"}

        INPUTS: NONE

       RESULTS: TRUE  = pushing successful
                FALSE = pushing failed (maybe stack full)

      SEE ALSO: @{" pop() " LINK fields_pop}

@endnode

@node fields_pop "Database / fields.pop()"

          NAME: pop(pos=TRUE)

   DESCRIPTION: restores the position in the field list previuosly stored
                on the stack with the @{"push()" LINK fields_push} method (LIFO).

                For more info see @{"nodemaster.pop()" LINK "Nodemaster.guide/Nodemaster_pop"}

        INPUTS: pos: TRUE  = restores the old position
                     FALSE = only removes the position from the stack

       RESULTS: pointer to a dbfield object if pop() succeded
                FALSE if pop() failed or pos=FALSE

      SEE ALSO: @{" push() " LINK fields_push}

@endnode

@node fields_obj "Database / fields.obj()"

          NAME: obj()

   DESCRIPTION: returns the pointer to the dbfield object in the current
                position of the field list

        INPUTS: NONE

       RESULTS: pointer to a dbfield object

      SEE ALSO:

@endnode

@node fields_clear "Database / fields.clear()"

          NAME: clear()

   DESCRIPTION: clears the list of field of the database object. The
                dbfield objects will be automatically deallocated.
                This method cannot be used when the table is open (in this
                case it will Raise a @{"DBASE_ERR_TABLEOPEN" LINK database_errortable} exception).

        INPUTS: NONE

       RESULTS: NONE

      SEE ALSO:
@endnode

@node fields_byname "Database / fields.byname()"

          NAME: byname(name)

   DESCRIPTION: moves to the field named "name" in the field list

        INPUTS: name of field to search for

       RESULTS: pointer to a dbfield object, or NIL if there is no field
                with such a name

      SEE ALSO: @{" first() " LINK fields_first}
                @{" succ()  " LINK fields_succ}
                @{" prev()  " LINK fields_prev}
                @{" last()  " LINK fields_last}

@endnode

@node fields_getattr "Database / fields.getattr()"

          NAME: getattr(tag)

   DESCRIPTION: returns the value of a field attribute.
                This method understands the following tags:

                DBFTAG_NAME   = name of field

                DBFTAG_TYPE   = type of field

                DBFTAG_LENGTH = length of field

                DBFTAG_REQUIRED = required flag of field


        INPUTS: one of the tags above

       RESULTS: current value of the chosen attribute

      SEE ALSO: @{" add() " LINK fields_add}

@endnode

@node fields_setv "Database / fields.setv()"

          NAME: setv(value)

   DESCRIPTION: sets the current field contents. The "value" parameter can
                be a number or a pointer to a more complex object
                (depending on the type of the current field).
                More complex fields (like the built-in @{"Memo" LINK type_memo}) may offer some
                extra methods to set (and get) their contents (see the
                @{"introduction" LINK database_general} for more info).

                You can change the contents of the fields only if you first
                called the database @{"add()" LINK database_add} or the database @{"edit()" LINK database_edit} method,
                otherwise this method will raise the @{"DBASE_ERR_NOMODE" LINK database_errortable}
                exception.

        INPUTS: new value to be assigned to the current field

       RESULTS: NONE

                This method raises the @{"DBASE_ERR_NOMODE" LINK database_errortable} exception if the
                database is neither in the ADD nor EDIT mode.

      SEE ALSO: @{" getv() " LINK fields_getv}

@endnode

@node fields_getv "Database / fields.getv()"

          NAME: getv()

   DESCRIPTION: returns the current field contents. The value returned can
                be a number or a pointer to a more complex object
                (depending on the type of the current field).
                More complex fields (like the built-in @{"Memo" LINK type_memo}) may offer some
                extra methods to set (and get) their contents (see the
                @{"introduction" LINK database_general} for more info).

        INPUTS: NONE

       RESULTS: contents of the current field

      SEE ALSO: @{" setv() " LINK fields_setv}

@endnode

@node fields_asstring "Database / fields.asString()"

          NAME: asString(s)

   DESCRIPTION: converts the value of the current field to a string and
                copies it in the string "s". This method has been included
                for display purposes.

        INPUTS: s = pointer to an already allocated string

       RESULTS: s (the same pointer you passed)

      SEE ALSO:

@endnode

@node fields_assign "Database / fields.assign()"

          NAME: assign(p)

   DESCRIPTION: copies the contents of the field pointed to by "p" to the
                current field.
                You can use this method to copy one field to another
                without knowing the internal structure of the two fields.
                Of course the source and destination fields must be of the
                same type, otherwise this method will Raise the
                @{"DBASE_ERR_NOMATCHFIELD" LINK database_errortable} exception.

        INPUTS: "p" pointer to the source dbfield object

       RESULTS: NONE

      SEE ALSO:

@endnode

@node index_add "Database / index.add()"

          NAME: add(field_name, index_type)

   DESCRIPTION: adds a new index. The field_name parameter contains the
                name of the field to be indexed; the index_type can only
                assume the value

                DBINDEX_PRIMARY

                meaning that the index is a primary index; this constant
             ->   can be ORed with the following constant
     not     ->
     yet     ->   DBINDEX_UNIQUE
 implemented ->
             ->   In this case no two records can have the same value in the
             ->   specified indexed field, otherwise it will be raised a
             ->   @{"DBASE_ERR_KEYVIOLATION" LINK database_errortable} exception.

                You can only add indexes to a closed table.

                Note that not all field types may support indexes (this
                behaviour is specified by the developer of the particular
                field type): if you try to index a field type that cannot
                be indexed, it will be raised the @{"DBASE_ERR_NOINDEXFIELD" LINK database_errortable}
                exception.

                Indexes are not limited to the first fields of the table
                (as happens for most database engines).

        INPUTS: field_name = name of field to be indexed
                index_type = type of index

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_TABLEOPEN           if the table is open

                DBASE_ERR_NOINDEXFIELD        if the field doesn't support
                                              indexing

                DBASE_ERR_INDEXEXISTS         if the field is already
                                              indexed

                DBASE_ERR_FIELDDOESNTEXIST    if the specified field
                                              doesn't exist

      SEE ALSO: @{" del() " LINK index_del}

@endnode

@node index_first "Database / index.first()"

          NAME: first()

   DESCRIPTION: moves to the first index of the current table.

        INPUTS: NONE

       RESULTS: FALSE if there are no indexes linked to the table

      SEE ALSO: @{" succ() " LINK index_succ}
                @{" prev() " LINK index_prev}
                @{" last() " LINK index_last}

@endnode

@node index_succ "Database / index.succ()"

          NAME: succ()

   DESCRIPTION: moves to the next index of the current table.

        INPUTS: NONE

       RESULTS: FALSE if there are no more indexes to go to (tail of list
                reached)

      SEE ALSO: @{" first() " LINK index_first}
                @{" prev()  " LINK index_prev}
                @{" last()  " LINK index_last}

@endnode

@node index_prev "Database / index.prev()"

          NAME: prev()

   DESCRIPTION: moves to the preceding index of the current table.

        INPUTS: NONE

       RESULTS: FALSE if there are no more indexes to go to (head of list
                reached)

      SEE ALSO: @{" succ()  " LINK index_succ}
                @{" first() " LINK index_first}
                @{" last()  " LINK index_last}

@endnode

@node index_last "Database / index.last()"

          NAME: last()

   DESCRIPTION: moves to the last index of the current table.

        INPUTS: NONE

       RESULTS: FALSE if there are no indexes linked to the table

      SEE ALSO: @{" succ()  " LINK index_succ}
                @{" prev()  " LINK index_prev}
                @{" first() " LINK index_first}

@endnode

@node index_clear "Database / index.clear()"

          NAME: clear()

   DESCRIPTION: removes all the indexes from the current table.

                Note that the table must be open to remove the available
                indexes; the index file will be emptied the next time the
                table is closed.

        INPUTS: NONE

       RESULTS: NONE

      SEE ALSO: @{" del() " LINK index_del}
                @{" add() " LINK index_add}

@endnode

@node index_del "Database / index.del()"

          NAME: del()

   DESCRIPTION: removes the current index.

                Note that the table must be open to remove the available
                indexes; the index file will be updated the next time the
                table is closed.

        INPUTS: NONE

       RESULTS: NONE

      SEE ALSO: @{" clear() " LINK index_clear}
                @{" add()   " LINK index_add}

@endnode

@node index_byname "Database / index.byname()"

          NAME: byname(index_name)

   DESCRIPTION: moves to the index with name "index_name".

        INPUTS: index_name = name of the index to move to

       RESULTS: NIL if the required index has not been found

      SEE ALSO: @{" first() " LINK index_first}
                @{" succ()  " LINK index_succ}
                @{" prev()  " LINK index_prev}
                @{" last()  " LINK index_last}

@endnode

@node index_name "Database / index.name()"

          NAME: name()

   DESCRIPTION: returns the name of the current index.

        INPUTS: NONE

       RESULTS: name of current index

      SEE ALSO: @{" type() " LINK index_type}
               
@endnode

@node index_type "Database / index.type()"

          NAME: type()

   DESCRIPTION: returns the type of the current index. For a list of
                available index types (and flags) refer to the @{"add()" LINK index_add}
                method.

        INPUTS: NONE

       RESULTS: type of current index

      SEE ALSO: @{" name() " LINK index_name}

@endnode

@node search_first "Database / search.first()"

          NAME: first()

   DESCRIPTION: moves to the first record satisfying the latest @{"locate()" LINK database_locate}
                criteria. This method (and all its relatives: @{"succ()" LINK search_succ},
                @{"prev()" LINK search_prev} and @{"last()" LINK search_last}) works just like the fields.first()
                method, but its range is restricted to the list of the
                results of the latest search. In particular, the fields
                will be automatically filled with the values stored in the
                record found.

        INPUTS: NONE

       RESULTS: FALSE if there are no records found

      SEE ALSO: @{" succ() " LINK search_succ}
                @{" prev() " LINK search_prev}
                @{" last() " LINK search_last}
               
@endnode

@node search_succ "Database / search.succ()"

          NAME: succ()

   DESCRIPTION: moves to the next record matching the latest @{"locate()" LINK database_locate}
                criteria.

        INPUTS: NONE

       RESULTS: FALSE if there are no more records found (tail of list
                reached)

      SEE ALSO: @{" first() " LINK search_first}
                @{" prev()  " LINK search_prev}
                @{" last()  " LINK search_last}
               
@endnode

@node search_prev "Database / search.prev()"

          NAME: prev()

   DESCRIPTION: moves to the previous record matching the latest @{"locate()" LINK database_locate}
                criteria.

        INPUTS: NONE

       RESULTS: FALSE if there are no more records found (head of list
                reached)

      SEE ALSO: @{" first() " LINK search_first}
                @{" succ()  " LINK search_succ}
                @{" last()  " LINK search_last}

@endnode

@node search_last "Database / search.last()"

          NAME: last()

   DESCRIPTION: moves to the last record matching the latest @{"locate()" LINK database_locate}
                criteria.

        INPUTS: NONE

       RESULTS: FALSE if there are no records found

      SEE ALSO: @{" first() " LINK search_first}
                @{" prev()  " LINK search_prev}
                @{" succ()  " LINK search_succ}

@endnode

@node search_numitems "Database / search.numitems()"

          NAME: numitems()

   DESCRIPTION: returns the number of records found by the latest @{"locate()" LINK database_locate}
                call.

        INPUTS: NONE

       RESULTS: number of records found

      SEE ALSO:

@endnode

@node database_database "Database / database()"

          NAME: database(name=NIL)

   DESCRIPTION: database object constructor. The "name" parameter contains
                the name of the table to be opened. If you don't want to
                pass the name of the table while allocating the database
                object, you have to set it afterwards with the @{"tablename()" LINK database_tablename}
                method.

        INPUTS: name = name of (the file containing) the table to be
                       opened. Obviuosly the name must be supplied with
                       full path.

       RESULTS: NONE

      SEE ALSO: @{" tablename() " LINK database_tablename}

@endnode

@node database_open "Database / open()"

          NAME: open()

   DESCRIPTION: opens the table. The name of (the file containing) the
                table is set while allocating the database object (with the
                @{"database()" LINK database_database} method) or with the use of the @{"tablename()" LINK database_tablename}
                method.

        INPUTS: NONE

       RESULTS: NONE

                This method Raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_NOTABLENAME   if table name not supplied

                DBASE_ERR_IOERR         if something went wrong with the
                                        file I/O routines

                DBASE_ERR_NOAFCD        if the main file is not an AFC
                                        database file

                DBASE_ERR_NOAFCB        if the blob file is not an AFC
                                        database file

                DBASE_ERR_VERSION       if the structure version of the
                                        file is different from the current
                                        version used by the object (maybe
                                        the file is an older database
                                        version)

                DBASE_ERR_NODATAFILE    if there are blob fields but
                                        there's no associated #?.data file
                                        containing their data

      SEE ALSO: @{" close()     " LINK database_close}
                @{" create()    " LINK database_create}
                @{" database()  " LINK database_database}
                @{" tablename() " LINK database_tablename}

@endnode

@node database_create "Database / create()"

          NAME: create()

   DESCRIPTION: creates a new table. The name of (the file that will
                contain) the table is set while allocating the database
                object (with the @{"database()" LINK database_database} method) or with the use
                of the @{"tablename()" LINK database_tablename} method.

                Before calling this method you have to add to the database
                object all the fields and the indexes that the table will
                contain (see @{"Steps to create a table" LINK database_createtable} for more info).

                After a table has been created it is open for use.


        INPUTS: NONE

                This method Raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_NOTABLENAME   if table name not supplied

                DBASE_ERR_IOERR         if something went wrong with the
                                        file I/O routines

                DBASE_ERR_NOFIELDS      if there are no fields linked to
                                        the database object

       RESULTS: NONE

      SEE ALSO: @{" open()      " LINK database_open}
                @{" close()     " LINK database_close}
                @{" database()  " LINK database_database}
                @{" tablename() " LINK database_tablename}

@endnode

@node database_close "Database / close()"

          NAME: close()

   DESCRIPTION: closes an open table. This method doesn't dispose of the
                database object, so you can reopen the same table or change
                the name of the table before opening another one with the
                same database object.

        INPUTS: NONE

       RESULTS: NONE

      SEE ALSO: @{" open()   " LINK database_open}
                @{" create() " LINK database_create}

@endnode

@node database_tablename "Database / tablename()"

          NAME: tablename(name)

   DESCRIPTION: changes the name of the table associated with the Database
                object. The name of a table is simply the name of the file
                containing the table (with full path).
                You have to enter the name of the table before opening it
                using either this method or passing such a name as a
                parameter of the @{"Database object constructor" LINK database_database}.
                You cannot change the name of the table while it is open,
                otherwise this method will raise the @{"DBASE_ERR_TABLEOPEN" LINK database_errortable}
                exception.

                If the name parameter is NIL or is the empty string this
                method doesn't change the name of the table but only
                returns the current table name.

        INPUTS: name of the file containing the table

       RESULTS: current name of the file containing the table

      SEE ALSO: @{" database() " LINK database_database}
                @{" open()     " LINK database_open}

@endnode

@node database_add "Database / add()"

          NAME: add()

   DESCRIPTION: puts the database in the ADD mode. The contents of all the
                fields will be cleared. After you filled in all the fields
                you call the @{"update()" LINK database_update} method to store the new record in the
                currently open table: the new record will be appended in
                the last position in the table.

                Note that if you move to another record your changes will
                be lost and you have to reissue the add() method to add a
                new record.

        INPUTS: NONE

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_TABLECLOSED   if the table is closed

                DBASE_ERR_READONLY      if the table is read only

      SEE ALSO: @{" update() " LINK database_update}
                @{" edit()   " LINK database_edit}

@endnode

@node database_edit "Database / edit()"

          NAME: edit()

   DESCRIPTION: puts the database in the EDIT mode. After you called this
                method you can change the contents of the fields; then you
                call the @{"update()" LINK database_update} method to write the changes to the table
                files.

                Note that if you move to another record your changes will
                be lost and you have to reissue the edit() method to change
                the contents of the current record.

        INPUTS: NONE

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_TABLECLOSED   if the table is closed

                DBASE_ERR_READONLY      if the table is read only

      SEE ALSO: @{" update() " LINK database_update}
                @{" add()    " LINK database_add}

@endnode

@node database_update "Database / update()"

          NAME: update()

   DESCRIPTION: writes the new fields contents to the table files. If the
                database was in the @{"ADD" LINK database_add} mode then a new record is appended
                to the end of the table; if the database was in the @{"EDIT" LINK database_edit}
                mode then the changes to the fields contents are written to
                the current record in the table files.

                After an update() has been issued, both the ADD and EDIT
                modes will be switched off: if you want to make other
                changes to your table you have to call again the @{"add()" LINK database_add} or
                the @{"edit()" LINK database_edit} method.

        INPUTS: NONE

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_TABLECLOSED   if the table is closed

                DBASE_ERR_NOMODE        if the database is neither in the
                                        ADD nor in the EDIT mode

                DBASE_ERR_IOERR         if something went wrong in the I/O
                                        routines (in this case the system
                                        call IoErr() will return the error
                                        number)

      SEE ALSO: @{" add()  " LINK database_add}
                @{" edit() " LINK database_edit}

@endnode

@node database_delete "Database / delete()"

          NAME: delete()

   DESCRIPTION: removes the current record from the table. The record is
                not physically removed, but it is only marked for deletion
                and from this time on it cannot be accessed.
                To free the room associated to removed records you have to
                call the @{"pack()" LINK database_pack} method.

        INPUTS: NONE

       RESULTS: NONE

                This method raises the @{"DBASE_ERR_TABLECLOSED" LINK database_errortable} exception if
                the table is closed.

      SEE ALSO: @{" add() " LINK database_add}

@endnode

@node database_first "Database / first()"

          NAME: first()

   DESCRIPTION: moves to the first record of the table. The fields contents
                will be automatically read from the table files.

        INPUTS: NONE

       RESULTS: FALSE if something went wrong while reading the record or
                if the table is empty; otherwise TRUE.

                This method raises the @{"DBASE_ERR_TABLECLOSED" LINK database_errortable} exception if
                the table is closed.

      SEE ALSO: @{" succ() " LINK database_succ}
                @{" prev() " LINK database_prev}
                @{" last() " LINK database_last}

@endnode

@node database_succ "Database / succ()"

          NAME: succ()

   DESCRIPTION: moves to the next record of the table. The fields contents
                will be automatically read from the table files.

        INPUTS: NONE

       RESULTS: FALSE if there are no more records in the table or
                if the table is empty; otherwise TRUE.

                This method raises the @{"DBASE_ERR_TABLECLOSED" LINK database_errortable} exception if
                the table is closed.

      SEE ALSO: @{" first() " LINK database_first}
                @{" prev()  " LINK database_prev}
                @{" last()  " LINK database_last}

@endnode

@node database_prev "Database / prev()"

          NAME: prev()

   DESCRIPTION: moves to the previous record of the table. The fields
                contents will be automatically read from the table files.

        INPUTS: NONE

       RESULTS: FALSE if there are no more records in the table or
                if the table is empty; otherwise TRUE.

                This method raises the @{"DBASE_ERR_TABLECLOSED" LINK database_errortable} exception if
                the table is closed.

      SEE ALSO: @{" succ()  " LINK database_succ}
                @{" first() " LINK database_first}
                @{" last()  " LINK database_last}

@endnode

@node database_last "Database / last()"

          NAME: last()

   DESCRIPTION: moves to the last record of the table. The fields contents
                will be automatically read from the table files.

        INPUTS: NONE

       RESULTS: FALSE if something went wrong while reading the record or
                if the table is empty; otherwise TRUE.

                This method raises the @{"DBASE_ERR_TABLECLOSED" LINK database_errortable} exception if
                the table is closed.

      SEE ALSO: @{" succ()  " LINK database_succ}
                @{" prev()  " LINK database_prev}
                @{" first() " LINK database_first}

@endnode

@node database_recordcount "Database / recordCount()"

          NAME: recordCount()

   DESCRIPTION: returns the number of records contained in the current
                table.

        INPUTS: NONE

       RESULTS: number of records of the table

      SEE ALSO:

@endnode

@node database_readonly "Database / readOnly()"

          NAME: readOnly(flag=TRUE)

   DESCRIPTION: if flag is TRUE then the table is put in a read-only state:
                you can only read it, but not modify it.
                The read-only status can be modified only when the table is
                closed, otherwise this method has no effect.

        INPUTS: read-only state

       RESULTS: NONE

      SEE ALSO:

@endnode

@node database_pack "Database / pack()"

          NAME: pack()

   DESCRIPTION: physically removes the deleted records from the table
                files.
                If you call the @{"delete()" LINK database_delete} method the current record is only
                marked for deletion and cannot longer be accessed. To free
                the room occupied by deleted records you have to call the
                pack() method.

                You can only pack closed tables.

        INPUTS: NONE

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_TABLEOPEN   if the table is open

                DBASE_ERR_NOMEM       if something went wrong with the
                                      memory allocating routines

                DBASE_ERR_NOFIELDS    if the table has no fields linked to
                                      it

      SEE ALSO: @{" delete() " LINK database_delete}

@endnode

@node database_dbftypeadd "Database / dbftypeadd()"

          NAME: dbftypeadd(id, proc)

   DESCRIPTION: links a custom field type to the Database engine: from this
                time on, the Database engine recognizes and uses the new
                field type (see the @{"Extra field types" LINK database_extratypes} section for more
                info).

                "id" is the identification constant of the new field type
                and "proc" is the procedure that is used as a constructor
                for the extra field class. The documentation of the extra
                field type must tell you what are the values that these
                parameters take on.

                Remember that you have to link an extra field type before a
                table containing such a field type is opened (or created),
                otherwise the @{"open()" LINK database_open} or @{"create()" LINK database_create} methods will raise an
                exception.

        INPUTS: id   = identification constant
                proc = ADDRESS of the constructor PROCEDURE

       RESULTS: NONE

                This method raises the @{"DBASE_ERR_CLASSEXISTS" LINK database_errortable} exception if
                the identification constant is already used by another
                class currently linked to the Database engine.

      SEE ALSO: @{" Extra field types section " LINK database_extratypes}

           BTW: the instructions to create a custom field class are
                contained in another guide.

@endnode

@node database_locate "Database / locate()"

          NAME: locate(field_list, values_list, mode=DBASE_LO_CASESENSITIVE)

   DESCRIPTION: searches through the table and lists all the records
                satisfying the request. The "field_list" parameter is a
                NIL-terminated list of field NAMES you want to search; the
                "values_list" parameter is a list of corresponding values
                you want to search for. Obviously fields and values must be
                in the same order.
                The mode parameter is necessary only if you are performing
                searches on string fields (DBFIELD_STRING) or on field
                types that exploit the internal string-matching routine;
                the mode parameter can be one of the following:

                  DBASE_LO_CASESENSITIVE    string matching is case
                                            sensitive (default)

                  DBASE_LO_CASEINSENSITIVE  string matching is case
                                            insensitive


                If a field is indexed, then the @{"index" LINK database_index} will be automatically
                used, speeding up the search process.

                The records found will be linked to the @{"search" LINK database_search} property of
                the Database object: you can move through them using the
                methods of the search property.

                Note: string search accepts standard AmigaDOS pattern
                matching.

        INPUTS: field_list  = NIL-term list of field names
                values_list = list of values to search for
                mode        = string matching mode

       RESULTS: NONE

                This method raises the following @{"exceptions" LINK database_errortable}:

                DBASE_ERR_NOMEM             if something went wrong with
                                            the memory management routines

                DBASE_ERR_FIELDDOESNTEXIST  if you passed a field name that
                                            is not linked to the table

      SEE ALSO: @{" search property " LINK database_search}

@endnode

@node database_currRec "Database / currRec()"

          NAME: currRec()

   DESCRIPTION: returns the current record number. The first record is
                record number 1.

        INPUTS: NONE

       RESULTS: current record number

      SEE ALSO: @{" recordCount() " LINK database_recordcount}

@endnode

@node database_version "Database / version()"

          NAME: version()

   DESCRIPTION: returns version and revision of the Database class

        INPUTS: NONE

       RESULTS: version, revision of Database class

      SEE ALSO:

@endnode

