aboutsummaryrefslogtreecommitdiffstats
path: root/slib.info-2
diff options
context:
space:
mode:
Diffstat (limited to 'slib.info-2')
-rw-r--r--slib.info-21193
1 files changed, 1193 insertions, 0 deletions
diff --git a/slib.info-2 b/slib.info-2
new file mode 100644
index 0000000..f1c31c5
--- /dev/null
+++ b/slib.info-2
@@ -0,0 +1,1193 @@
+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
+