diff options
Diffstat (limited to 'slib.info-2')
-rw-r--r-- | slib.info-2 | 1193 |
1 files changed, 0 insertions, 1193 deletions
diff --git a/slib.info-2 b/slib.info-2 deleted file mode 100644 index f1c31c5..0000000 --- a/slib.info-2 +++ /dev/null @@ -1,1193 +0,0 @@ -This is Info file slib.info, produced by Makeinfo-1.64 from the input -file slib.texi. - - This file documents SLIB, the portable Scheme library. - - Copyright (C) 1993 Todd R. Eigenschink Copyright (C) 1993, 1994, 1995 -Aubrey Jaffer - - Permission is granted to make and distribute verbatim copies of this -manual provided the copyright notice and this permission notice are -preserved on all copies. - - Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - - Permission is granted to copy and distribute translations of this -manual into another language, under the above conditions for modified -versions, except that this permission notice may be stated in a -translation approved by the author. - - -File: slib.info, Node: Records, Next: Base Table, Prev: Queues, Up: Data Structures - -Records -======= - - `(require 'record)' - - The Record package provides a facility for user to define their own -record data types. - - - Function: make-record-type TYPE-NAME FIELD-NAMES - Returns a "record-type descriptor", a value representing a new data - type disjoint from all others. The TYPE-NAME argument must be a - string, but is only used for debugging purposes (such as the - printed representation of a record of the new type). The - FIELD-NAMES argument is a list of symbols naming the "fields" of a - record of the new type. It is an error if the list contains any - duplicates. It is unspecified how record-type descriptors are - represented. - - - Function: record-constructor RTD [FIELD-NAMES] - Returns a procedure for constructing new members of the type - represented by RTD. The returned procedure accepts exactly as - many arguments as there are symbols in the given list, - FIELD-NAMES; these are used, in order, as the initial values of - those fields in a new record, which is returned by the constructor - procedure. The values of any fields not named in that list are - unspecified. The FIELD-NAMES argument defaults to the list of - field names in the call to `make-record-type' that created the - type represented by RTD; if the FIELD-NAMES argument is provided, - it is an error if it contains any duplicates or any symbols not in - the default list. - - - Function: record-predicate RTD - Returns a procedure for testing membership in the type represented - by RTD. The returned procedure accepts exactly one argument and - returns a true value if the argument is a member of the indicated - record type; it returns a false value otherwise. - - - Function: record-accessor RTD FIELD-NAME - Returns a procedure for reading the value of a particular field of - a member of the type represented by RTD. The returned procedure - accepts exactly one argument which must be a record of the - appropriate type; it returns the current value of the field named - by the symbol FIELD-NAME in that record. The symbol FIELD-NAME - must be a member of the list of field-names in the call to - `make-record-type' that created the type represented by RTD. - - - Function: record-modifier RTD FIELD-NAME - Returns a procedure for writing the value of a particular field of - a member of the type represented by RTD. The returned procedure - accepts exactly two arguments: first, a record of the appropriate - type, and second, an arbitrary Scheme value; it modifies the field - named by the symbol FIELD-NAME in that record to contain the given - value. The returned value of the modifier procedure is - unspecified. The symbol FIELD-NAME must be a member of the list - of field-names in the call to `make-record-type' that created the - type represented by RTD. - - - Function: record? OBJ - Returns a true value if OBJ is a record of any type and a false - value otherwise. Note that `record?' may be true of any Scheme - value; of course, if it returns true for some particular value, - then `record-type-descriptor' is applicable to that value and - returns an appropriate descriptor. - - - Function: record-type-descriptor RECORD - Returns a record-type descriptor representing the type of the given - record. That is, for example, if the returned descriptor were - passed to `record-predicate', the resulting predicate would return - a true value when passed the given record. Note that it is not - necessarily the case that the returned descriptor is the one that - was passed to `record-constructor' in the call that created the - constructor procedure that created the given record. - - - Function: record-type-name RTD - Returns the type-name associated with the type represented by rtd. - The returned value is `eqv?' to the TYPE-NAME argument given in - the call to `make-record-type' that created the type represented by - RTD. - - - Function: record-type-field-names RTD - Returns a list of the symbols naming the fields in members of the - type represented by RTD. The returned value is `equal?' to the - field-names argument given in the call to `make-record-type' that - created the type represented by RTD. - - -File: slib.info, Node: Base Table, Next: Relational Database, Prev: Records, Up: Data Structures - -Base Table -========== - - A base table implementation using Scheme association lists is -available as the value of the identifier `alist-table' after doing: - - (require 'alist-table) - - Association list base tables are suitable for small databases and -support all Scheme types when temporary and readable/writeable Scheme -types when saved. I hope support for other base table implementations -will be added in the future. - - This rest of this section documents the interface for a base table -implementation from which the *Note Relational Database:: package -constructs a Relational system. It will be of interest primarily to -those wishing to port or write new base-table implementations. - - All of these functions are accessed through a single procedure by -calling that procedure with the symbol name of the operation. A -procedure will be returned if that operation is supported and `#f' -otherwise. For example: - - (require 'alist-table) - (define open-base (alist-table 'make-base)) - make-base => *a procedure* - (define foo (alist-table 'foo)) - foo => #f - - - Function: make-base FILENAME KEY-DIMENSION COLUMN-TYPES - Returns a new, open, low-level database (collection of tables) - associated with FILENAME. This returned database has an empty - table associated with CATALOG-ID. The positive integer - KEY-DIMENSION is the number of keys composed to make a PRIMARY-KEY - for the catalog table. The list of symbols COLUMN-TYPES describes - the types of each column for that table. If the database cannot - be created as specified, `#f' is returned. - - Calling the `close-base' method on this database and possibly other - operations will cause FILENAME to be written to. If FILENAME is - `#f' a temporary, non-disk based database will be created if such - can be supported by the base table implelentation. - - - Function: open-base FILENAME MUTABLE - Returns an open low-level database associated with FILENAME. If - MUTABLE? is `#t', this database will have methods capable of - effecting change to the database. If MUTABLE? is `#f', only - methods for inquiring the database will be available. If the - database cannot be opened as specified `#f' is returned. - - Calling the `close-base' (and possibly other) method on a MUTABLE? - database will cause FILENAME to be written to. - - - Function: write-base LLDB FILENAME - Causes the low-level database LLDB to be written to FILENAME. If - the write is successful, also causes LLDB to henceforth be - associated with FILENAME. Calling the `close-database' (and - possibly other) method on LLDB may cause FILENAME to be written - to. If FILENAME is `#f' this database will be changed to a - temporary, non-disk based database if such can be supported by the - underlying base table implelentation. If the operations completed - successfully, `#t' is returned. Otherwise, `#f' is returned. - - - Function: sync-base LLDB - Causes the file associated with the low-level database LLDB to be - updated to reflect its current state. If the associated filename - is `#f', no action is taken and `#f' is returned. If this - operation completes successfully, `#t' is returned. Otherwise, - `#f' is returned. - - - Function: close-base LLDB - Causes the low-level database LLDB to be written to its associated - file (if any). If the write is successful, subsequent operations - to LLDB will signal an error. If the operations complete - successfully, `#t' is returned. Otherwise, `#f' is returned. - - - Function: make-table LLDB KEY-DIMENSION COLUMN-TYPES - Returns the BASE-ID for a new base table, otherwise returns `#f'. - The base table can then be opened using `(open-table LLDB - BASE-ID)'. The positive integer KEY-DIMENSION is the number of - keys composed to make a PRIMARY-KEY for this table. The list of - symbols COLUMN-TYPES describes the types of each column. - - - Constant: catalog-id - A constant BASE-ID suitable for passing as a parameter to - `open-table'. CATALOG-ID will be used as the base table for the - system catalog. - - - Function: open-table LLDB BASE-ID KEY-DIMENSION COLUMN-TYPES - Returns a HANDLE for an existing base table in the low-level - database LLDB if that table exists and can be opened in the mode - indicated by MUTABLE?, otherwise returns `#f'. - - As with `make-table', the positive integer KEY-DIMENSION is the - number of keys composed to make a PRIMARY-KEY for this table. The - list of symbols COLUMN-TYPES describes the types of each column. - - - Function: kill-table LLDB BASE-ID KEY-DIMENSION COLUMN-TYPES - Returns `#t' if the base table associated with BASE-ID was removed - from the low level database LLDB, and `#f' otherwise. - - - Function: make-keyifier-1 TYPE - Returns a procedure which accepts a single argument which must be - of type TYPE. This returned procedure returns an object suitable - for being a KEY argument in the functions whose descriptions - follow. - - Any 2 arguments of the supported type passed to the returned - function which are not `equal?' must result in returned values - which are not `equal?'. - - - Function: make-list-keyifier KEY-DIMENSION TYPES - The list of symbols TYPES must have at least KEY-DIMENSION - elements. Returns a procedure which accepts a list of length - KEY-DIMENSION and whose types must corresopond to the types named - by TYPES. This returned procedure combines the elements of its - list argument into an object suitable for being a KEY argument in - the functions whose descriptions follow. - - Any 2 lists of supported types (which must at least include - symbols and non-negative integers) passed to the returned function - which are not `equal?' must result in returned values which are not - `equal?'. - - - Function: make-key-extractor KEY-DIMENSION TYPES COLUMN-NUMBER - Returns a procedure which accepts objects produced by application - of the result of `(make-list-keyifier KEY-DIMENSION TYPES)'. This - procedure returns a KEY which is `equal?' to the COLUMN-NUMBERth - element of the list which was passed to create COMBINED-KEY. The - list TYPES must have at least KEY-DIMENSION elements. - - - Function: make-key->list KEY-DIMENSION TYPES - Returns a procedure which accepts objects produced by application - of the result of `(make-list-keyifier KEY-DIMENSION TYPES)'. This - procedure returns a list of KEYs which are elementwise `equal?' to - the list which was passed to create COMBINED-KEY. - -In the following functions, the KEY argument can always be assumed to -be the value returned by a call to a *keyify* routine. - - - Function: for-each-key HANDLE PROCEDURE - Calls PROCEDURE once with each KEY in the table opened in HANDLE - in an unspecified order. An unspecified value is returned. - - - Function: map-key HANDLE PROCEDURE - Returns a list of the values returned by calling PROCEDURE once - with each KEY in the table opened in HANDLE in an unspecified - order. - - - Function: ordered-for-each-key HANDLE PROCEDURE - Calls PROCEDURE once with each KEY in the table opened in HANDLE - in the natural order for the types of the primary key fields of - that table. An unspecified value is returned. - - - Function: present? HANDLE KEY - Returns a non-`#f' value if there is a row associated with KEY in - the table opened in HANDLE and `#f' otherwise. - - - Function: delete HANDLE KEY - Removes the row associated with KEY from the table opened in - HANDLE. An unspecified value is returned. - - - Function: make-getter KEY-DIMENSION TYPES - Returns a procedure which takes arguments HANDLE and KEY. This - procedure returns a list of the non-primary values of the relation - (in the base table opened in HANDLE) whose primary key is KEY if - it exists, and `#f' otherwise. - - - Function: make-putter KEY-DIMENSION TYPES - Returns a procedure which takes arguments HANDLE and KEY and - VALUE-LIST. This procedure associates the primary key KEY with - the values in VALUE-LIST (in the base table opened in HANDLE) and - returns an unspecified value. - - - Function: supported-type? SYMBOL - Returns `#t' if SYMBOL names a type allowed as a column value by - the implementation, and `#f' otherwise. At a minimum, an - implementation must support the types `integer', `symbol', - `string', `boolean', and `base-id'. - - - Function: supported-key-type? SYMBOL - Returns `#t' if SYMBOL names a type allowed as a key value by the - implementation, and `#f' otherwise. At a minimum, an - implementation must support the types `integer', and `symbol'. - -`integer' - Scheme exact integer. - -`symbol' - Scheme symbol. - -`boolean' - `#t' or `#f'. - -`base-id' - Objects suitable for passing as the BASE-ID parameter to - `open-table'. The value of CATALOG-ID must be an acceptable - `base-id'. - - -File: slib.info, Node: Relational Database, Next: Weight-Balanced Trees, Prev: Base Table, Up: Data Structures - -Relational Database -=================== - - `(require 'relational-database)' - - This package implements a database system inspired by the Relational -Model (`E. F. Codd, A Relational Model of Data for Large Shared Data -Banks'). An SLIB relational database implementation can be created -from any *Note Base Table:: implementation. - -* Menu: - -* Motivations:: Database Manifesto -* Creating and Opening Relational Databases:: -* Relational Database Operations:: -* Table Operations:: -* Catalog Representation:: -* Unresolved Issues:: -* Database Utilities:: 'database-utilities - - -File: slib.info, Node: Motivations, Next: Creating and Opening Relational Databases, Prev: Relational Database, Up: Relational Database - -Motivations ------------ - - Most nontrivial programs contain databases: Makefiles, configure -scripts, file backup, calendars, editors, source revision control, CAD -systems, display managers, menu GUIs, games, parsers, debuggers, -profilers, and even error reporting are all rife with databases. Coding -databases is such a common activity in programming that many may not be -aware of how often they do it. - - A database often starts as a dispatch in a program. The author, -perhaps because of the need to make the dispatch configurable, the need -for correlating dispatch in other routines, or because of changes or -growth, devises a data structure to contain the information, a routine -for interpreting that data structure, and perhaps routines for -augmenting and modifying the stored data. The dispatch must be -converted into this form and tested. - - The programmer may need to devise an interactive program for enabling -easy examination and modification of the information contained in this -database. Often, in an attempt to foster modularity and avoid delays in -release, intermediate file formats for the database information are -devised. It often turns out that users prefer modifying these -intermediate files with a text editor to using the interactive program -in order to do operations (such as global changes) not forseen by the -program's author. - - In order to address this need, the concientous software engineer may -even provide a scripting language to allow users to make repetitive -database changes. Users will grumble that they need to read a large -manual and learn yet another programming language (even if it *almost* -has language "xyz" syntax) in order to do simple configuration. - - All of these facilities need to be designed, coded, debugged, -documented, and supported; often causing what was very simple in concept -to become a major developement project. - - This view of databases just outlined is somewhat the reverse of the -view of the originators of the "Relational Model" of database -abstraction. The relational model was devised to unify and allow -interoperation of large multi-user databases running on diverse -platforms. A fairly general purpose "Comprehensive Language" for -database manipulations is mandated (but not specified) as part of the -relational model for databases. - - One aspect of the Relational Model of some importance is that the -"Comprehensive Language" must be expressible in some form which can be -stored in the database. This frees the programmer from having to make -programs data-driven in order to use a database. - - This package includes as one of its basic supported types Scheme -"expression"s. This type allows expressions as defined by the Scheme -standards to be stored in the database. Using `slib:eval' retrieved -expressions can be evaluated (in the top-level environment). Scheme's -`lambda' facilitates closure of environments, modularity, etc. so that -procedures (which could not be stored directly most databases) can -still be effectively retrieved. Since `slib:eval' evaluates -expressions in the top-level environment, built-in and user defined -procedures can be easily accessed by name. - - This package's purpose is to standardize (through a common interface) -database creation and usage in Scheme programs. The relational model's -provision for inclusion of language expressions as data as well as the -description (in tables, of course) of all of its tables assures that -relational databases are powerful enough to assume the roles currently -played by thousands of ad-hoc routines and data formats. - -Such standardization to a relational-like model brings many benefits: - - * Tables, fields, domains, and types can be dealt with by name in - programs. - - * The underlying database implementation can be changed (for - performance or other reasons) by changing a single line of code. - - * The formats of tables can be easily extended or changed without - altering code. - - * Consistency checks are specified as part of the table descriptions. - Changes in checks need only occur in one place. - - * All the configuration information which the developer wishes to - group together is easily grouped, without needing to change - programs aware of only some of these tables. - - * Generalized report generators, interactive entry programs, and - other database utilities can be part of a shared library. The - burden of adding configurability to a program is greatly reduced. - - * Scheme is the "comprehensive language" for these databases. - Scripting for configuration no longer needs to be in a separate - language with additional documentation. - - * Scheme's latent types mesh well with the strict typing and logical - requirements of the relational model. - - * Portable formats allow easy interchange of data. The included - table descriptions help prevent misinterpretation of format. - - -File: slib.info, Node: Creating and Opening Relational Databases, Next: Relational Database Operations, Prev: Motivations, Up: Relational Database - -Creating and Opening Relational Databases ------------------------------------------ - - - Function: make-relational-system BASE-TABLE-IMPLEMENTATION - Returns a procedure implementing a relational database using the - BASE-TABLE-IMPLEMENTATION. - - All of the operations of a base table implementation are accessed - through a procedure defined by `require'ing that implementation. - Similarly, all of the operations of the relational database - implementation are accessed through the procedure returned by - `make-relational-system'. For instance, a new relational database - could be created from the procedure returned by - `make-relational-system' by: - - (require 'alist-table) - (define relational-alist-system - (make-relational-system alist-table)) - (define create-alist-database - (relational-alist-system 'create-database)) - (define my-database - (create-alist-database "mydata.db")) - -What follows are the descriptions of the methods available from -relational system returned by a call to `make-relational-system'. - - - Function: create-database FILENAME - Returns an open, nearly empty relational database associated with - FILENAME. The only tables defined are the system catalog and - domain table. Calling the `close-database' method on this database - and possibly other operations will cause FILENAME to be written - to. If FILENAME is `#f' a temporary, non-disk based database will - be created if such can be supported by the underlying base table - implelentation. If the database cannot be created as specified - `#f' is returned. For the fields and layout of descriptor tables, - *Note Catalog Representation:: - - - Function: open-database FILENAME MUTABLE? - Returns an open relational database associated with FILENAME. If - MUTABLE? is `#t', this database will have methods capable of - effecting change to the database. If MUTABLE? is `#f', only - methods for inquiring the database will be available. Calling the - `close-database' (and possibly other) method on a MUTABLE? - database will cause FILENAME to be written to. If the database - cannot be opened as specified `#f' is returned. - - -File: slib.info, Node: Relational Database Operations, Next: Table Operations, Prev: Creating and Opening Relational Databases, Up: Relational Database - -Relational Database Operations ------------------------------- - -These are the descriptions of the methods available from an open -relational database. A method is retrieved from a database by calling -the database with the symbol name of the operation. For example: - - (define my-database - (create-alist-database "mydata.db")) - (define telephone-table-desc - ((my-database 'create-table) 'telephone-table-desc)) - - - Function: close-database - Causes the relational database to be written to its associated - file (if any). If the write is successful, subsequent operations - to this database will signal an error. If the operations completed - successfully, `#t' is returned. Otherwise, `#f' is returned. - - - Function: write-database FILENAME - Causes the relational database to be written to FILENAME. If the - write is successful, also causes the database to henceforth be - associated with FILENAME. Calling the `close-database' (and - possibly other) method on this database will cause FILENAME to be - written to. If FILENAME is `#f' this database will be changed to - a temporary, non-disk based database if such can be supported by - the underlying base table implelentation. If the operations - completed successfully, `#t' is returned. Otherwise, `#f' is - returned. - - - Function: table-exists? TABLE-NAME - Returns `#t' if TABLE-NAME exists in the system catalog, otherwise - returns `#f'. - - - Function: open-table TABLE-NAME MUTABLE? - Returns a "methods" procedure for an existing relational table in - this database if it exists and can be opened in the mode indicated - by MUTABLE?, otherwise returns `#f'. - -These methods will be present only in databases which are MUTABLE?. - - - Function: delete-table TABLE-NAME - Removes and returns the TABLE-NAME row from the system catalog if - the table or view associated with TABLE-NAME gets removed from the - database, and `#f' otherwise. - - - Function: create-table TABLE-DESC-NAME - Returns a methods procedure for a new (open) relational table for - describing the columns of a new base table in this database, - otherwise returns `#f'. For the fields and layout of descriptor - tables, *Note Catalog Representation::. - - - Function: create-table TABLE-NAME TABLE-DESC-NAME - Returns a methods procedure for a new (open) relational table with - columns as described by TABLE-DESC-NAME, otherwise returns `#f'. - - - Function: create-view ?? - - Function: project-table ?? - - Function: restrict-table ?? - - Function: cart-prod-tables ?? - Not yet implemented. - - -File: slib.info, Node: Table Operations, Next: Catalog Representation, Prev: Relational Database Operations, Up: Relational Database - -Table Operations ----------------- - -These are the descriptions of the methods available from an open -relational table. A method is retrieved from a table by calling the -table with the symbol name of the operation. For example: - - (define telephone-table-desc - ((my-database 'create-table) 'telephone-table-desc)) - (require 'common-list-functions) - (define ndrp (telephone-table-desc 'row:insert)) - (ndrp '(1 #t name #f string)) - (ndrp '(2 #f telephone - (lambda (d) - (and (string? d) (> (string-length d) 2) - (every - (lambda (c) - (memv c '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 - #\+ #\( #\ #\) #\-))) - (string->list d)))) - string)) - -Operations on a single column of a table are retrieved by giving the -column name as the second argument to the methods procedure. For -example: - - (define column-ids ((telephone-table-desc 'get* 'column-number))) - -Some operations described below require primary key arguments. Primary -keys arguments are denoted KEY1 KEY2 .... It is an error to call an -operation for a table which takes primary key arguments with the wrong -number of primary keys for that table. - -The term "row" used below refers to a Scheme list of values (one for -each column) in the order specified in the descriptor (table) for this -table. Missing values appear as `#f'. Primary keys may not be missing. - - - Function: get KEY1 KEY2 ... - Returns the value for the specified column of the row associated - with primary keys KEY1, KEY2 ... if it exists, or `#f' otherwise. - - - Function: get* - Returns a list of the values for the specified column for all rows - in this table. - - - Function: row:retrieve KEY1 KEY2 ... - Returns the row associated with primary keys KEY1, KEY2 ... if it - exists, or `#f' otherwise. - - - Function: row:retrieve* - Returns a list of all rows in this table. - - - Function: row:remove KEY1 KEY2 ... - Removes and returns the row associated with primary keys KEY1, - KEY2 ... if it exists, or `#f' otherwise. - - - Function: row:remove* - Removes and returns a list of all rows in this table. - - - Function: row:delete KEY1 KEY2 ... - Deletes the row associated with primary keys KEY1, KEY2 ... if it - exists. The value returned is unspecified. - - - Function: row:delete* - Deletes all rows in this table. The value returned is - unspecified. The descriptor table and catalog entry for this - table are not affected. - - - Function: row:update ROW - Adds the row, ROW, to this table. If a row for the primary key(s) - specified by ROW already exists in this table, it will be - overwritten. The value returned is unspecified. - - - Function: row:update* ROWS - Adds each row in the list ROWS, to this table. If a row for the - primary key specified by an element of ROWS already exists in this - table, it will be overwritten. The value returned is unspecified. - - - Function: row:insert ROW - Adds the row ROW to this table. If a row for the primary key(s) - specified by ROW already exists in this table an error is - signaled. The value returned is unspecified. - - - Function: row:insert* ROWS - Adds each row in the list ROWS, to this table. If a row for the - primary key specified by an element of ROWS already exists in this - table, an error is signaled. The value returned is unspecified. - - - Function: for-each-row PROC - Calls PROC with each ROW in this table in the natural ordering for - the primary key types. *Real* relational programmers would use - some least-upper-bound join for every row to get them in order; - But we don't have joins yet. - - - Function: close-table - Subsequent operations to this table will signal an error. - - - Constant: column-names - - Constant: column-foreigns - - Constant: column-domains - - Constant: column-types - Return a list of the column names, foreign-key table names, domain - names, or type names respectively for this table. These 4 methods - are different from the others in that the list is returned, rather - than a procedure to obtain the list. - - - Constant: primary-limit - Returns the number of primary keys fields in the relations in this - table. - - -File: slib.info, Node: Catalog Representation, Next: Unresolved Issues, Prev: Table Operations, Up: Relational Database - -Catalog Representation ----------------------- - -Each database (in an implementation) has a "system catalog" which -describes all the user accessible tables in that database (including -itself). - -The system catalog base table has the following fields. `PRI' -indicates a primary key for that table. - - PRI table-name - column-limit the highest column number - coltab-name descriptor table name - bastab-id data base table identifier - user-integrity-rule - view-procedure A scheme thunk which, when called, - produces a handle for the view. coltab - and bastab are specified if and only if - view-procedure is not. - -Descriptors for base tables (not views) are tables (pointed to by -system catalog). Descriptor (base) tables have the fields: - - PRI column-number sequential integers from 1 - primary-key? boolean TRUE for primary key components - column-name - column-integrity-rule - domain-name - -A "primary key" is any column marked as `primary-key?' in the -corresponding descriptor table. All the `primary-key?' columns must -have lower column numbers than any non-`primary-key?' columns. Every -table must have at least one primary key. Primary keys must be -sufficient to distinguish all rows from each other in the table. All of -the system defined tables have a single primary key. - -This package currently supports tables having from 1 to 4 primary keys -if there are non-primary columns, and any (natural) number if *all* -columns are primary keys. If you need more than 4 primary keys, I would -like to hear what you are doing! - -A "domain" is a category describing the allowable values to occur in a -column. It is described by a (base) table with the fields: - - PRI domain-name - foreign-table - domain-integrity-rule - type-id - type-param - -The "type-id" field value is a symbol. This symbol may be used by the -underlying base table implementation in storing that field. - -If the `foreign-table' field is non-`#f' then that field names a table -from the catalog. The values for that domain must match a primary key -of the table referenced by the TYPE-PARAM (or `#f', if allowed). This -package currently does not support composite foreign-keys. - -The types for which support is planned are: - atom - symbol - string [<length>] - number [<base>] - money <currency> - date-time - boolean - - foreign-key <table-name> - expression - virtual <expression> - - -File: slib.info, Node: Unresolved Issues, Next: Database Utilities, Prev: Catalog Representation, Up: Relational Database - -Unresolved Issues ------------------ - - Although `rdms.scm' is not large I found it very difficult to write -(six rewrites). I am not aware of any other examples of a generalized -relational system (although there is little new in CS). I left out -several aspects of the Relational model in order to simplify the job. -The major features lacking (which might be addressed portably) are -views, transaction boundaries, and protection. - - Protection needs a model for specifying priveledges. Given how -operations are accessed from handles it should not be difficult to -restrict table accesses to those allowed for that user. - - The system catalog has a field called `view-procedure'. This should -allow a purely functional implementation of views. This will work but -is unsatisfying for views resulting from a "select"ion (subset of -rows); for whole table operations it will not be possible to reduce the -number of keys scanned over when the selection is specified only by an -opaque procedure. - - Transaction boundaries present the most intriguing area. Transaction -boundaries are actually a feature of the "Comprehensive Language" of the -Relational database and not of the database. Scheme would seem to -provide the opportunity for an extremely clean semantics for transaction -boundaries since the builtin procedures with side effects are small in -number and easily identified. - - These side-effect builtin procedures might all be portably redefined -to versions which properly handled transactions. Compiled library -routines would need to be recompiled as well. Many system extensions -(delete-file, system, etc.) would also need to be redefined. - -There are 2 scope issues that must be resolved for multiprocess -transaction boundaries: - -Process scope - The actions captured by a transaction should be only for the - process which invoked the start of transaction. Although standard - Scheme does not provide process primitives as such, `dynamic-wind' - would provide a workable hook into process switching for many - implementations. - -Shared utilities with state - Some shared utilities have state which should *not* be part of a - transaction. An example would be calling a pseudo-random number - generator. If the success of a transaction depended on the - pseudo-random number and failed, the state of the generator would - be set back. Subsequent calls would keep returning the same - number and keep failing. - - Pseudo-random number generators are not reentrant and so would - require locks in order to operate properly in a multiprocess - environment. Are all examples of utilities whose state should not - part of transactions also non-reentrant? If so, perhaps - suspending transaction capture for the duration of locks would fix - it. - - -File: slib.info, Node: Database Utilities, Prev: Unresolved Issues, Up: Relational Database - -Database Utilities ------------------- - - `(require 'database-utilities)' - -This enhancement wraps a utility layer on `relational-database' which -provides: - * Automatic loading of the appropriate base-table package when - opening a database. - - * Automatic execution of initialization commands stored in database. - - * Transparent execution of database commands stored in `*commands*' - table in database. - -Also included are utilities which provide: - * Data definition from Scheme lists and - - * Report generation - -for any SLIB relational database. - - - Function: create-database FILENAME BASE-TABLE-TYPE - Returns an open, nearly empty enhanced (with `*commands*' table) - relational database (with base-table type BASE-TABLE-TYPE) - associated with FILENAME. - - - Function: open-database FILENAME - - Function: open-database FILENAME BASE-TABLE-TYPE - Returns an open enchanced relational database associated with - FILENAME. The database will be opened with base-table type - BASE-TABLE-TYPE) if supplied. If BASE-TABLE-TYPE is not supplied, - `open-database' will attempt to deduce the correct - base-table-type. If the database can not be opened or if it lacks - the `*commands*' table, `#f' is returned. - - - Function: open-database! FILENAME - - Function: open-database! FILENAME BASE-TABLE-TYPE - Returns *mutable* open enchanced relational database ... - -The table `*commands*' in an "enhanced" relational-database has the -fields (with domains): - PRI name symbol - parameters parameter-list - procedure expression - documentation string - - The `parameters' field is a foreign key (domain `parameter-list') of -the `*catalog-data*' table and should have the value of a table -described by `*parameter-columns*'. This `parameter-list' table -describes the arguments suitable for passing to the associated command. -The intent of this table is to be of a form such that different -user-interfaces (for instance, pull-down menus or plain-text queries) -can operate from the same table. A `parameter-list' table has the -following fields: - PRI index uint - name symbol - arity parameter-arity - domain domain - default expression - documentation string - - The `arity' field can take the values: - -`single' - Requires a single parameter of the specified domain. - -`optional' - A single parameter of the specified domain or zero parameters is - acceptable. - -`boolean' - A single boolean parameter or zero parameters (in which case `#f' - is substituted) is acceptable. - -`nary' - Any number of parameters of the specified domain are acceptable. - The argument passed to the command function is always a list of the - parameters. - -`nary1' - One or more of parameters of the specified domain are acceptable. - The argument passed to the command function is always a list of the - parameters. - - The `domain' field specifies the domain which a parameter or -parameters in the `index'th field must satisfy. - - The `default' field is an expression whose value is either `#f' or a -procedure of no arguments which returns a parameter or parameter list -as appropriate. If the expression's value is `#f' then no default is -appropriate for this parameter. Note that since the `default' -procedure is called every time a default parameter is needed for this -column, "sticky" defaults can be implemented using shared state with -the domain-integrity-rule. - -Invoking Commands -................. - - When an enhanced relational-database is called with a symbol which -matches a NAME in the `*commands*' table, the associated procedure -expression is evaluated and applied to the enhanced -relational-database. A procedure should then be returned which the user -can invoke on (optional) arguments. - - The command `*initialize*' is special. If present in the -`*commands*' table, `open-database' or `open-database!' will return the -value of the `*initialize*' command. Notice that arbitrary code can be -run when the `*initialize*' procedure is automatically applied to the -enhanced relational-database. - - Note also that if you wish to shadow or hide from the user -relational-database methods described in *Note Relational Database -Operations::, this can be done by a dispatch in the closure returned by -the `*initialize*' expression rather than by entries in the -`*commands*' table if it is desired that the underlying methods remain -accessible to code in the `*commands*' table. - - - Function: make-command-server RDB TABLE-NAME - Returns a procedure of 2 arguments, a (symbol) command and a - call-back procedure. When this returned procedure is called, it - looks up COMMAND in table TABLE-NAME and calls the call-back - procedure with arguments: - COMMAND - The COMMAND - - COMMAND-VALUE - The result of evaluating the expression in the PROCEDURE - field of TABLE-NAME and calling it with RDB. - - PARAMETER-NAME - A list of the "official" name of each parameter. Corresponds - to the `name' field of the COMMAND's parameter-table. - - POSITIONS - A list of the positive integer index of each parameter. - Corresponds to the `index' field of the COMMAND's - parameter-table. - - ARITIES - A list of the arities of each parameter. Corresponds to the - `arity' field of the COMMAND's parameter-table. For a - description of `arity' see table above. - - DEFAULTS - A list of the defaults for each parameter. Corresponds to - the `defaults' field of the COMMAND's parameter-table. - - DOMAIN-INTEGRITY-RULES - A list of procedures (one for each parameter) which tests - whether a value for a parameter is acceptable for that - parameter. The procedure should be called with each datum in - the list for `nary' arity parameters. - - ALIASES - A list of lists of `(alias parameter-name)'. There can be - more than one alias per PARAMETER-NAME. - - For information about parameters, *Note Parameter lists::. Here is an -example of setting up a command with arguments and parsing those -arguments from a `getopt' style argument list (*note Getopt::.). - - (require 'database-utilities) - (require 'parameters) - (require 'getopt) - - (define my-rdb (create-database #f 'alist-table)) - - (define-tables my-rdb - '(foo-params - *parameter-columns* - *parameter-columns* - ((1 first-argument single string "hithere" "first argument") - (2 flag boolean boolean #f "a flag"))) - '(foo-pnames - ((name string)) - ((parameter-index uint)) - (("l" 1) - ("a" 2))) - '(my-commands - ((name symbol)) - ((parameters parameter-list) - (parameter-names parameter-name-translation) - (procedure expression) - (documentation string)) - ((foo - foo-params - foo-pnames - (lambda (rdb) (lambda (foo aflag) (print foo aflag))) - "test command arguments")))) - - (define (dbutil:serve-command-line rdb command-table - command argc argv) - (set! argv (if (vector? argv) (vector->list argv) argv)) - ((make-command-server rdb command-table) - command - (lambda (comname comval options positions - arities types defaults dirs aliases) - (apply comval (getopt->arglist argc argv options positions - arities types defaults dirs aliases))))) - - (define (test) - (set! *optind* 1) - (dbutil:serve-command-line - my-rdb 'my-commands 'foo 4 '("dummy" "-l" "foo" "-a"))) - (test) - -| - "foo" #t - - Some commands are defined in all extended relational-databases. The -are called just like *Note Relational Database Operations::. - - - Function: add-domain DOMAIN-ROW - Adds DOMAIN-ROW to the "domains" table if there is no row in the - domains table associated with key `(car DOMAIN-ROW)' and returns - `#t'. Otherwise returns `#f'. - - For the fields and layout of the domain table, *Note Catalog - Representation:: - - - Function: delete-domain DOMAIN-NAME - Removes and returns the DOMAIN-NAME row from the "domains" table. - - - Function: domain-checker DOMAIN - Returns a procedure to check an argument for conformance to domain - DOMAIN. - -Defining Tables ---------------- - - - Procedure: define-tables RDB SPEC-0 ... - Adds tables as specified in SPEC-0 ... to the open - relational-database RDB. Each SPEC has the form: - - (<name> <descriptor-name> <descriptor-name> <rows>) - or - (<name> <primary-key-fields> <other-fields> <rows>) - - where <name> is the table name, <descriptor-name> is the symbol - name of a descriptor table, <primary-key-fields> and - <other-fields> describe the primary keys and other fields - respectively, and <rows> is a list of data rows to be added to the - table. - - <primary-key-fields> and <other-fields> are lists of field - descriptors of the form: - - (<column-name> <domain>) - or - (<column-name> <domain> <column-integrity-rule>) - - where <column-name> is the column name, <domain> is the domain of - the column, and <column-integrity-rule> is an expression whose - value is a procedure of one argument (and returns non-`#f' to - signal an error). - - If <domain> is not a defined domain name and it matches the name of - this table or an already defined (in one of SPEC-0 ...) single key - field table, a foriegn-key domain will be created for it. - - - Procedure: create-report RDB DESTINATION REPORT-NAME TABLE - - Procedure: create-report RDB DESTINATION REPORT-NAME - The symbol REPORT-NAME must be primary key in the table named - `*reports*' in the relational database RDB. DESTINATION is a - port, string, or symbol. If DESTINATION is a: - - port - The table is created as ascii text and written to that port. - - string - The table is created as ascii text and written to the file - named by DESTINATION. - - symbol - DESTINATION is the primary key for a row in the table named - *printers*. - - Each row in the table *reports* has the fields: - - name - The report name. - - default-table - The table to report on if none is specified. - - header, footer - A `format' string. At the beginning and end of each page - respectively, `format' is called with this string and the - (list of) column-names of this table. - - reporter - A `format' string. For each row in the table, `format' is - called with this string and the row. - - minimum-break - The minimum number of lines into which the report lines for a - row can be broken. Use `0' if a row's lines should not be - broken over page boundaries. - - Each row in the table *printers* has the fields: - - name - The printer name. - - print-procedure - The procedure to call to actually print. - - The report is prepared as follows: - - `Format' (*note Format::.) is called with the `header' field - and the (list of) `column-names' of the table. - - `Format' is called with the `reporter' field and (on - successive calls) each record in the natural order for the - table. A count is kept of the number of newlines output by - format. When the number of newlines to be output exceeds the - number of lines per page, the set of lines will be broken if - there are more than `minimum-break' left on this page and the - number of lines for this row is larger or equal to twice - `minimum-break'. - - `Format' is called with the `footer' field and the (list of) - `column-names' of the table. The footer field should not - output a newline. - - A new page is output. - - This entire process repeats until all the rows are output. - -The following example shows a new database with the name of `foo.db' -being created with tables describing processor families and -processor/os/compiler combinations. - -The database command `define-tables' is defined to call `define-tables' -with its arguments. The database is also configured to print `Welcome' -when the database is opened. The database is then closed and reopened. - - (require 'database-utilities) - (define my-rdb (create-database "foo.db" 'alist-table)) - - (define-tables my-rdb - '(*commands* - ((name symbol)) - ((parameters parameter-list) - (procedure expression) - (documentation string)) - ((define-tables - no-parameters - no-parameter-names - (lambda (rdb) (lambda specs (apply define-tables rdb specs))) - "Create or Augment tables from list of specs") - (*initialize* - no-parameters - no-parameter-names - (lambda (rdb) (display "Welcome") (newline) rdb) - "Print Welcome")))) - - ((my-rdb 'define-tables) - '(processor-family - ((family atom)) - ((also-ran processor-family)) - ((m68000 #f) - (m68030 m68000) - (i386 8086) - (8086 #f) - (powerpc #f))) - - '(platform - ((name symbol)) - ((processor processor-family) - (os symbol) - (compiler symbol)) - ((aix powerpc aix -) - (amiga-dice-c m68000 amiga dice-c) - (amiga-aztec m68000 amiga aztec) - (amiga-sas/c-5.10 m68000 amiga sas/c) - (atari-st-gcc m68000 atari gcc) - (atari-st-turbo-c m68000 atari turbo-c) - (borland-c-3.1 8086 ms-dos borland-c) - (djgpp i386 ms-dos gcc) - (linux i386 linux gcc) - (microsoft-c 8086 ms-dos microsoft-c) - (os/2-emx i386 os/2 gcc) - (turbo-c-2 8086 ms-dos turbo-c) - (watcom-9.0 i386 ms-dos watcom)))) - - ((my-rdb 'close-database)) - - (set! my-rdb (open-database "foo.db" 'alist-table)) - -| - Welcome - |