home *** CD-ROM | disk | FTP | other *** search
- /\
- / \
- ../ \....METALBASE Version 5.0..............................................
- / \
- / \ Written From October 1990 by Huan-Ti
- \ /
- \ / Revision 3.1 released December 10th 1990
- \ / Revision 3.2 released December 10th 1991
- \ / Revision 4.0 released Febuary 14th 1992
- \/ Revision 4.1 released April 1st 1992
- Revision 4.1a released May 10th 1992
- Revision 5.0 released October 1st 1992
-
-
-
-
-
-
- "And Calvin ate. And Food Lion went out of business. Amen."
-
- --1st Calvin 4:8
-
-
- WHY_METALBASE_?________________________________________________________________
-
- The Amiga 500 multi-tasks. Wow. It has great graphics. Yeah. Phenomenal
- sound. Yippee. It costs $500. I bought one.
- A DBase package costs more than the computer. So does Paradox. And
- Informix. And almost every other database package on the market. I didn't
- buy one.
- But I needed a database for my system--anybody who's ever worked with a
- database knows they're addictive; code that's written without a flexible
- database backing it up lacks something. And DBase wants $600 to put that
- something back into programs. No thanks.
- That's why MetalBase was written... its forerunners (versions 1.0 and
- 2.0, not available) were designed by the same author with the Amiga line's
- needs specifically in mind: relatively slow floppy drives (Compared to hard
- drives), so sparse read-head maneuvering was essential. Relatively small
- memory, when compared with the amounts of memory required by most C compilers
- (Lattice needs roughly 300k just to run, for example), so the code had to be
- consise, pure, and use few variables. Expansion was always available; hard
- drives, huge memory capacities, extra processors, ram drives -- so the system
- had to be readily expandible and flexible enough to meet the requirements of
- both a 512k, 1-drive machine and a 32-megabyte, 200-meg hard drive-driven
- setup. And they were.
- The problem was, Amigas can multi-task. So what is the rest of the
- computer doing while a database runs around looking up records on one drive?
- Nothing. Why not let it look up records on another drive? Fine... that works.
- What about on the same drive... using, say, a ram disk, so there are no real
- read-heads to worry about positioning? That would mean each relation would
- have to support multi-user access... a requirement around which MetalBase
- versions 3.0 and up focus. Not only can any given terminal access many files
- at once, but on multi-terminal systems, each terminal can work simultaneously
- on any given file. Terminals can each use as many relations as a system will
- allow, and each relation can be used by some sixty-four users at once. The
- code used to create MetalBase 3.X and up is completely compatible with the
- Unix operating system and all of its derivatives, so its inherent multi-user
- ability places it in firm working footing on the most advanced systems on the
- market.
- But the IBM users complained. And the unix users complained. And lo,
- even the Amiga people complained--the code didn't work all the time, and
- was generally crude. So MetalBase 4.0 solved these troubles and more--a
- complete rewrite of the engine has provided even faster and more efficient
- algorithms, which keep MetalBase indices in AVL balance at all times. More
- convenient functions and operations (such as build's ability to create header
- files for your code which reflect a schema's structure) have been added,
- along with several utility programs for maintaining your database.
- Relations are designed by a user to match his/her exact requirements,
- indices placed as needed on single or composite fields, and records can be
- added, retrieved, changed, and deleted as any C programmer so desires. The
- interface is as simple as possible, very fast in execution, and provides a wide
- range of error types for exact specification of problems. A user on any
- terminal can choose to lock out other users from any number of relations, so
- sweeping changes in data will not be read by others before they can take
- place. Automatic temporary locks are placed on a relation which is about
- to undergo a deletion or addition, strategically delaying other users' access
- to files for less than seconds, so that no data will be read until all indices
- have been updated correctly. This process is entirely system-driven; users
- never need worry about it at all. If one user is adding a record to a
- relation, any terminal requesting a record lookup will simply wait until the
- addition is complete before proceeding. As records are deleted and added
- through normal use, the algorithms used to update indices automatically keep
- them at top operating speeds, so any given relation's number of records can
- grow exponentially while causing only a linear increase in look-up time. Any
- relation can contain over four billion records (Nearly four billion more than
- most systems will ever need), and each record's length can be as large as its
- system's memory can handle. In perspective, MetalBase is infinitely
- expandible, while requiring very little of the system on which it operates.
-
- [ The actual number of records allowable is 4,294,967,296... if you were to
- add one record a second, it would take over 136 years to reach this limit ]
-
- RELATION_DESIGN________________________________________________________________
-
- A sample relation. Data Field # -> 1 2 3 4 5
- is read by selecting one Record # _____ ___ ____ ___ ___________
- record from the others by 1 |_____|___|____|___|___________|
- various criteria, and 2 |_____|___|____|___|___________|
- returning it to the user. 3 |Smith| 12| 114| A2|Houston, TX|
- Record 3 (In this example-- 4 |-----|---|----|---|-----------|
- actual MetalBase records need
- no such numbering system), if returned, would be placed in a structure
- containing Smith,12,114,A2, and Houston,TX in the appropriate elements.
-
- A relation is a collection of records, each record consisting of the same
- number of fields--blocks of data whose individual lengths remain constant from
- record to record. Each field need not have the same length as the others in
- any given record, but from record to record, a field's length will remain the
- same. The data the fields contain is, of course, the main purpose of a
- database--when thousands of records exist, a system without a database would
- need vast amounts of time to find any given record. Databases decrease
- dramatically record retrieval time, while requiring as little additional time
- to add new and change old records as possible.
- The key to a database is its indices--pointers arranged in such a fashion
- as to show the system where to look for the record for which it is searching.
- The more of these collections of pointers, or indices, a database has, the
- greater the number of different fields a system can search through in order to
- find a record meeting certain criteria for a field (Or fields... a single index
- can be used to first sort records by one field, and also sort duplicates with
- respect to a second field, etc. MetalBase allows these composite indices to
- key off of as many as 999 different fields). However, databases require time
- to update each index every time you add, delete, or change a field which has an
- index placed upon it. So although retrieval criteria possibilites are expanded
- by using many indices, the amount of time required to change the existing
- records in a database will also increase. For this reason, the number of
- indices a relation will have should be considered carefully--use what is
- needed, but no more.
-
- Relations are built from schema files, which decribe the relation in a
- more human-friendly syntax. See build.dox for a more complete description of
- this process.
-
- IMPLEMENTAION__________________________________________________________________
-
- A sample program implementing MetalBase follows:
-
- #include <mbase.h>
- #include "equipment.h"
-
- main ()
- {
- relation *rel;
-
- if ((rel = mb_inc ("/usr/joe/equipment", strtokey("key"))) == RNULL) {
- printf ("Can't open database - %s.\n", mb_error);
- mb_exit (1);
- }
-
- equipment_rec.price_code = 114.20; /* Set up initial values */
- strcpy (equipment_rec.part_numb, "117"); /* to search for... */
-
- if (mb_sel (rel, 0, &equipment_rec, EQUAL, NULL) != 0) {
- printf ("%s.\n", mb_error);
- mb_exit (1);
- }
-
- /* Now that we've found a record, change it to something else... */
-
- equipment_rec.num_purch = 14;
- strcpy (equipment_rec.customer, "Su");
- strcpy (equipment_rec.part_numb, "112");
- strcpy (equipment_rec.shop_addr, "Dallas, TX");
- equipment_rec.price_code = 12;
-
- mb_upd (rel, &equipment_rec); /* Update the current selection */
-
- mb_rmv (rel); // Unnecessary before mb_exit(), but good practice.
- mb_exit (0); // Always a good idea to use mb_exit() with MetalBase.
- }
-
- Manipulation of relations using MetalBase is simple... by including the
- MetalBase header file in your programs and compiling using the option "-lmb"
- (Or "library ..., mbase.lib;", depending on your compiler), you add extra
- commands to C. A summary of these follows:
-
- - mb_inc (filename, int) -- this command includes a relation on your desktop,
- so that it becomes accessable. Any relation you wish to work with
- must be included using this call. If mb_inc returns RNULL ( defined
- as (relation *)0 ), an error has occurred (The most likely one is that
- the relation cannot be found under the given directory--mb_errno will
- be set to an error number, and mb_error (global char*) will contain
- text regarding the problem). Note that "filename" does NOT include the
- ".rel" suffix. BUILD, in analog, does not require that you include the
- ".s" suffix on the name of the schema you are working with, but the
- schema file itself must end in ".s", as relations must end in ".rel",
- forms in ".frm" and reports in ".rpt".
-
- The integer passed in is the encryption key for the relation--see the
- section on encryption for more information. Note that MetalBase 3.0,
- as it does not support encryption, does not require this integer; all
- versions 3.1 and up do. Sorry for the inconvenience.
-
- I also STRONGLY recommend the use of the function strtokey() to
- obtain this integer from an ascii string... all utility programs
- shipped with MetalBase ask for "Encryption Key"s, and they expect
- a string to hash up with strtokey(). So if you use encryption but
- not this method of getting the integer, you're SOL when trying to
- use vr or report. In fact, I encourage this so strongly that, in
- future releases, I may replace the integer argument with a string
- argument and do away with strtokey() entirely.
-
- - mb_tst (filename) -- This function goes through all the steps needed to
- make sure a given relation can be opened, but doesn't open it (thus
- it doesn't need an encryption key). vr uses this one to make sure
- it can open a relation before asking for a key; that's pretty much
- its only use.
-
- - mb_sel (file, index, buffer, action, comparison_buffer) -- this command
- searches a given relation for the record you desire, described by
- "action" and "comparison_value". "file" is a pointer to the structure
- returned by mb_inc... this structure is used in all other functions to
- indicate which relation you intend to work with. "index" is the index
- number by which you wish to search... numbered sequentially by the
- order in which they were defined in the schema, starting with the
- number 0. To save trouble when changing schema, it is recommended you
- use the routine idxnum() to look up an index number by name. "buffer"
- is merely a structure (like &equipment_rec above) into which MetalBase
- can return the record, when found. A list of valid actions follows:
- FIRST (or FRST) -- searches for the first record alphabetically.
- LAST -- similarly, seeks the last record alphabetically.
- NEXT -- searches for the next sequential record alphabetically.
- PREVIOUS (PREV) -- as NEXT, searches for the previous record.
- EQUAL (EQUL) -- seeks a record containing fields exactly those in
- "comparison_buffer". If the index used allows duplicates and
- some exist, EQUAL returns the first of these: all duplicates
- can be found by subsequent "NEXT" searches. Note that the
- comparison_buffer and the return buffer need not be the same
- space, although they may.
- GTEQ -- EQUAL returns a NOT_FOUND error if a record cannot be found
- to precisely match the comparison. GTEQ acts as EQUAL in all
- respects but this; GTEQ will find the record greater
- alphabetically, or precisely equal to (if one exists), the
- comparison. In the event that duplicates of the record exist
- ("Duplicate" being defined logically as a record whose fields
- used by the current index are precisely equal to another such
- record's fields for the same index), GTEQ returns the first
- of these: all duplicates can be found by subsequent "NEXT"
- searches.
- GTHAN (GTHN) -- Acts as GTEQ, except GTHAN will ignore precise
- matches. Useful if you wish to begin searching names, say,
- after the "Smith"'s. Another way to accomplish this would be
- to use LTEQ + "Smith", followed by a NEXT...
- LTEQ -- Searches for a record less alphabetically, or equal to (if
- one exists), the comparison. In the event that duplicates of
- the record about to be returned exist, LTEQ returns the last of
- these: all duplicates can be found by subsequent "PREVIOUS"
- searches.
- LTHN (LTHAN) -- Similar to LTEQ in all but one regard: LTHAN will
- not return a precise duplicate, instead searching to its
- left for the record before it.
- CURR (CURRENT) -- After a record is found by a search, MetalBase
- remembers the location of the record. Searching with the
- action CURRENT re-reads this most recent record, and returns
- it in its entirety. As with FIRST, LAST, NEXT and PREVIOUS,
- the value of "comparison_value" is irrelevant in CURRENT --
- however, CURRENT is also oblivious to index used (As no
- actual searching takes place... MetalBase merely recalls a
- known record).
- Please note that the above-described action names merely stand for
- integers, and MetalBase will not understand if you use quotes around
- the names. These actions must also be written in upper-case.
- "comparison_buffer" is a structure identical to "buffer", but any
- data in any of the fields is used for comparison when searching for
- EQUAL, GTEQ, LTEQ, GTHAN or LTHAN. There are three ways to use that--
- give it a new record...
- sample_str sample_rec, target_rec;
- target_rec.num = 15;
- mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, &target_rec)
- or, the same one twice...
- sample_str sample_rec;
- sample_rec.num = 15;
- mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, &sample_rec)
- or, what I do most, pass in NULL as the comparison (works just like
- the one above):
- sample_str sample_rec;
- sample_rec.num = 15;
- mb_sel (rel, idxnum("ix_num"), &sample_rec, EQUAL, NULL)
- All three of these would have the same effect.
-
- - mb_upd (file, new_rec) -- After a record is found, it may be updated
- through mb_upd. MetalBase simply replaces the old record's fields with
- those indicated in "new_rec". This process usually requires more time
- than any other, as the record must be disconnected from each index in
- turn, changed, and reconnected. Occasionally, changing a record will
- not change certain indices--when this occurs, the index is simply
- skipped. An update, like an add, will be aborted if the changes would
- violate a no-duplicates-allowed index.
-
- - mb_del (file) -- After a record is found, it may be removed completely by
- use of mb_del. Once a record is deleted thus, it CANNOT be retrieved.
- Pre-5.0 versions of MetalBase used a second argument for tracking the
- current pointer; this code was broken and I removed it. :) So now
- there's no second argument--again, sorry for changing things on ya.
-
- - mb_add (file, new_rec) -- This command adds a new record to a relation. If
- adding the record described by "new_rec" would violate a non-duplicate
- index, the addition to the relation will be aborted and an error
- returned (See the section on Errors, below).
-
- - mb_lck (file) -- If, as an example, a program reads a record from a relation
- used by many terminals simulaneously, waits for a user to enter a new
- value for one of its fields, and updates the record, it could prove
- disastrous if the record was read by one terminal, then another...
- updated on one & re-written, and re-updated by the second terminal. To
- prevent this type of scenario, mb_lck, when used, excludes other users
- from reading or writing to a relation. Every operation they try
- (including mb_inc()) will return MB_LOCKED until the process which
- called mb_lck() calls mb_unl().
-
- - mb_unl (file) -- Removes a lock placed on a relation by mv_lck.
-
- - mb_rmv (file) -- This command removes a relation from your desktop. If the
- file has been locked previously (via mb_lck), the lock is removed.
-
- - mb_die () -- This command removes all open relations from your desktop, as
- if you'd called each one in turn with mb_rmv(file).
-
- - mb_exit (ret_code) -- Calls mb_die(), followed by exit(ret_code).
-
- - mb_num (file) -- Returns the number of records in a relation. Wheeee...
-
-
- ERRORS_________________________________________________________________________
-
- In addition, see the separate documentation on troubleshooting, under the name
- trouble.dox. There's not much, but I tried...
-
- Build / Errors :
-
- Cannot open <file.s>............The schema indicated to Build cannot
- be found.
- File <file.s> holds no schema...The schema indicated cannot be used
- definition as a definition of a relation. The
- most likely cause is that the file is
- empty.
- Field <field> declared after....All fields must be declared before any
- indices indices are declared.
- Field <field> declared twice....Field names must be unique. Spaces are
- not allowed in field names.
- No fields declared before.......A relation must contain fields, and these
- end reached must be declared before any indices.
- Incorrect syntax................The definition of a field's length has
- been entered incorrectly.
- Field <field> undefined.........An index has been placed on a non-
- existant field. Check spelling.
- No fields declared before end...The schema definition is incomplete: it
- reached must contain at least one field and
- one index.
- No indices declared before.....See the above error description.
- end reached
- Identifier <?> not recognized...The only valid words for the beginning
- of a line are "relation" or a relation-
- name (as the first line), "field",
- "index", and (optionally) "end".
- Cannot open relation............The file <file.rel> cannot be written...
- possible causes are a media error or
- write-protection on the file.
- Relation is busy................Relations cannot be re-built until it is
- not being worked with by any users.
- The file about to be created....If you build a relation where a relation
- already exists of the same name already exists, any
- data in the existing relation will be
- erased in favor of the new, empty
- relation.
-
- MetalBase / Errors :
-
- MetalBase routines either return necessary information (such as, mb_inc()
- returns a relation-pointer, and mb_num() the number of records in a relation),
- or 0 to indicate success. The global variable mb_errno will be set to MB_OKAY
- (0) on success, and another error number (in the 1000's) on failure; the
- variable mb_error is a character string which will always describe the most
- recent error. Possible errors are:
-
- 0..MB_OKAY............This is the generic no-problem return code. All
- functions except mb_inc should return 0 if
- they have been able to function properly.
- 1001..MB_NO_ROOM.........Too many relations are open at once -- mb_inc
- cannot allocate enough space for the new
- relation. This error can be prevented by
- re-defining MAX_REL, as with build's warning
- messages, to a value greater than its default
- of 5. In addition, having many files open at
- once may require that you warn <stdio.h>
- (or config.sys, if you're using MSDOS)...
- consult your system manuals.
- 1002..MB_NO_MEMORY.......A malloc() has failed, and the task must be
- aborted. This is a bad, bad thing to happen.
- How d'ya fix it? Well, that's hard to say...
- look around and make sure you're free()'ing any
- memory you malloc().
- 1003..MB_NO_OPEN.........The file "file.rel", where "file" is the name
- passed to mb_inc, cannot be opened. In all
- probability, it does not exist.
- 1004..MB_NO_READ.........The file <file.rel> cannot be read. This error
- is returned only from mb_inc, and is probably
- caused by read-protection placed on the file.
- 1005..MB_FORMAT..........This is the generic this-shouldn't-have-happened
- error. Check out trouble.dox for a quick
- explanation of what could cause it.
- 1006..MB_LOCKED..........This error is returned if another user has
- locked the relation you're trying to access...
- wait until they haven't, and you'll be fine.
- 1007..MB_BUSY............Only a certain number of users is allowed to
- access a relation at any given time. The
- limits are:
- MetalBase 3.1, 3.2.........120
- MetalBase 4.0...............63
- MetalBase 4.1, 4.1a, 5.0...255
- 1008..MB_BAD_REL.........This essentially means that the relation* you
- passed to a function was not returned by
- a call to mb_inc()... it's an invalid pointer.
- 1009..MB_NO_WRITE........This error is produced when the relation you've
- opened can't be written to... perhaps you don't
- have permission.
- 1010..MB_TIMEOUT.........A user has stopped a program during a record
- addition, deletion, or update. These functions
- place temporary locks on a file, which are
- removed at the end of their respective
- procedures. Normally other functions will
- simply wait for the file to be unlocked, but if
- the wait time becomes excessive, this error is
- returned and the function aborted. Try the
- function again, and if you recieve this error
- a second time, see the section on Utilites to
- remove the lock manually.
-
- Note that this error is no longer used, as of
- revision 4.1.
- 1011..MB_BAD_REC.........A null pointer to a record has been received.
- So essentially, you've given NULL instead
- of &rec. Stupid thing to do. :(
- 1012..MB_CORRUPT.........This relation has an error on an index. See the
- section on Utilites to repair it. Try to find
- which index you were working with at the time
- of the error, in order to speed repair.
- 1013..MB_BAD_DUP.........The record that has been offered for addition/
- update would violate an index that has been
- declared not to allow duplicates.
- 1014..MB_NO_CURR.........In order to perform a delete or an update,
- you must have already issued mb_sel() to
- determine which record you wish to modify.
- This error indicates you have not done so.
- 1015..MB_BAD_IDX.........A bad index number has been passed to mb_sel.
- Valid numbers range 0 through the number of
- indices in a relation, minus 1.
- 1016..MB_NO_SUCH.........Generic code returned when the record described
- cannot be found in the relation searched. If
- you feel it should have been found, check the
- index number, action, and comparison value used
- in the search.
- 1017..MB_UNKNOWN.........A very unlikely error, receipt of this code
- indicates you have passed a number greater than
- 12 or less than 0 to mb_sel as an action.
- 1018..MB_NO_FIELDS.......You're trying to create a new relation without
- specifying any fields for it. Stupid you.
- 1019..MB_NO_INDICES......You're trying to create a new relation without
- specifying any inidces for it.
- 1020..MB_BAD_INDEX.......An index you're trying to create has no fields.
- Remember that the format for indices being
- created is "nnn,nnn,nnn" --no whitespace
- allowed without using BUILD.
- 1021..MB_DISKFULL........This will only happen on mb_add() or when using
- mbconv, the 4.0+ => 5.0 conversion utility,
- and is returned whenever there isn't enough
- free space on the drive to perform the
- requested operation.
- 1022..MB_BAD_SERIAL......This will only happen on mb_upd(), if you've
- changed the serial number of the record
- you're trying to update. You can't. It won't
- let you.
- 1023..MB_TMPDIR..........On some systems, MetalBase requires that you
- have the environment variable "TMP" set to
- an appropriate directory for temporary files;
- for example, "TMP=/tmp; export TMP" or
- "set TMP=C:\TMP". If you prefer, you can
- use the variable "TEMP" instead.
- 1024..MB_TMPERR..........MetalBase cannot work with the directory you've
- defined as per error #1023 (see TROUBLE.DOX).
-
- UTILITIES______________________________________________________________________
-
- Five utilities have been released with this package; one, called blast,
- removes user- and system-placed locks on a relation and sets the number of
- users the relation thinks are using it to zero. Impromper closing of a
- relation (ie, not closing one) will cause the number of users to build up
- until it cannot be used any longer.
-
- The second utility included is called vr, for View Relation. Please see
- the separate documentation under ../dox/vr.dox for its description and
- instructions for its use.
-
- The third utility is called report... it generates reports of a relation's
- contents. There is sparse documentation under ../dox/report.dox; it might
- help, it might not. Play with it and it'll work--honest. :)
-
- The fourth, and newest utility, is called mbconv--it converts pre-5.0
- MetalBase relations to 5.0 syntax. Note that the process is safe but
- irreversable; and your schema files may need semicolons added just to be
- complete.
-
- And, the final utility is called "form"--it compiles data-entry templates
- into .h files your programs include for data-entry. There's practically
- no documentation; just the one example under ../sample. Good luck to you.
-
- Other supporting utilities to MetalBase have not been released with this
- package, primarily because I have not bothered to write them yet. See the
- ReadMe.Too file up one directory to see how to register yourself with me, as
- I'll write any of the following upon request once you're registered (and
- maybe before, if I have time).
-
- Future utilities:
-
- * Repair of bad indices and recover of unreclaimed space from
- previous deletes
-
- * Utility to change a relation's schema without destroying its
- contents (oh boy...)
-
- * Relation import/export from standard, Emailable text files.
-
-
- ENCRYPTION______________________________________________________________________
-
- MetalBase 3.1 and up (not 3.0) automatically encrypt all files unless
- told otherwise. When a relation is opened (using mb_inc()), an integer
- encryption-key is passed in to MetalBase. Any records which are added to that
- relation are encrypted using this key, and any records which are retrieved are
- decrypted similarly before they are returned. In this way, any information
- which is physically stored is encrypted beyond recognition. As long as this
- integer key is the same every time the relation is opened, the encryption is
- totally user-transparent: records are passed to mb_inc and mb_upd in normal
- text, and are retrieved in normal text, but are stored garbled. If the key
- changes, however, the records retreived in the second session will be decrypted
- under the new key, whereas they were encrypted under the former... and the
- output will be meaningless, for numbers and strings alike.
-
- Note that the encryption is apparently working for ALL supported machines
- now--however, this has always been the hardest part to port between machines.
- If necessary (or if you simply want to), compile mbase.c (and vr.c/sample.c/
- whatever) with -DNOENCRYPT, and it'll be turned off.
-
- For a more thorough explanation of MetalBase's encryption process, see the
- separate documentation crypt.dox.
-
- --
- ___
- .-',' /\
- / (_______.------------------. / \ Huan-Ti
- ( _______|))))))))))))))))))| \ /
- )__( `------------------' \/
- `----' richid@owlnet.rice.edu
-
-