Index | Contents | Up

CLOS-DB Programmer Interface

Version 2.0, 29-Sep-92

Christoph Wernhard
info@cs.christophwernhard.com

Contents

1. Introduction

CLOS-DB is a database interface for the Common Lisp Object System.

At the definition of classes with the metaclass live-db-class or snapshot-db-class (live db classes resp. snapshot db classes), a database correspondence can be specified.

Valid superclasses of db classes are classes with the metaclass standard-class and other db classes, where the database correspondence is inherited.

Instances of db classes can be created for given database related object identifiers (e.g. relational key values). Creation of many instances of a class corresponding to a single such object identifier can be suppressed: the instances are then identified by their class and the object identifier. Instances of db classes can also be created (or identified) setwise corresponding to a given search condition and as members of a given class (instances of the class and its subclasses).

An instance of a live db class at each point of time represents the database in its actual state: database updates, that are executed whenever a slot is written, can be specified; slots and object identities can be invalidated to reflect changes in the database (the data corresponding to the instance then are loaded from the database anew); subobjects can be lazily created.

An instance of a snapshot db class represents a ``snapshot'' of the database at a certain point of time. No database updates can be associated with snaphot db instances, they can not be invalidated and subobjects may not be created lazily.

Instances of live db classes as well as snapshot db classes can have ``normal'' slots without database correspondence. Instances of live db classes can have ``snapshot'' slots which represent the database at a certain point of time.

The connection to relational databases is implemented using Database Representatives, a lower level database interface that makes relational databases accessible through interpreters for database queries and commands. This lower level interface remains visible in the CLOS-DB programmer interface.

CLOS-DB can be portably implemented using the CLOS Metaobject Protocol AMOP [AMOP].

2. Db Classes

2.1. The Metaclasses db-class, live-db-class and snapshot-db-class

The metaclasses live-db-class and snapshot-db-class are subclasses of standard-class. db-class, also a subclass of standard-class, is an abstract (i.e. not intended to be initialized) superclass of live-db-class and snapshot-db-class.

In the following we call instances of live-db-class live db classes, instances of snapshot-db-class snapshot db classes and instances of either one of both metaclasses db classes. Instances of db classes, live db classes and snapshot db classes are called db instances, live db instances or snapshot db instances respectively.

Db classes have a database correspondence associated with them. At their definition a mapping between the class and databases can be specified.

The class t, instances of standard-class and db classes are valid superclasses of db classes. Db classes are valid subclasses of db classes.

2.2. Abstract Superclasses of All Db Classes

The class db-object is an abstract superclass of each db class, live-db-object of each live db class and snapshot-db-object of each snapshot db class. These abstract superclasses are automatically added to the set of superclasses of a db class. In the class precedence list of a given db class they are preceded by the user specified superclasses of the given db class, live-db-object and snapshot-db-object precede db-object and db-object precedes standard-object.

2.3. Defining Db Classes

[Macro]
def-db-class

For technical reasons db classes have to be defined by the the def-db-class macro, which is similar to the defclass macro.

The evaluation or execution of a def-db-class form that defines a db class involves no database access.

2.4. Additional Class and Slot Options for Db Classes

[Class Option]
db-connection db-connection-type db-connection-arguments

This class option is accepted by db classes and is used to specify a database object (e.g. a relation of a relational database) as corresponding to the class. The db-connection-type argument specifies the kind of database connection: the keyword :relational stands for a connection to a relational database as described in section 3. Which arguments are accepted as db-connection-arguments depends on db-connection-type.

[Class Option]
abstract-member-class boolean

This class option is accepted by db classes and is used in connection with the make-member[-xxx] and identify-member[-xxx] functions. See section 2.7.

[Slot Option]
db-update form

This slot option is accepted by live db classes only and is used to specifiy database updates that should be executed when the slot is written. See section 5.1.

[Slot Option]
invalidateable boolean

This slot option is accepted by live db classes only and is used to specify whether slots are invalidateable. See section 6.

2.5. Attribute Variables in Initforms

An instance of a db class corresponds to values for a fixed set of attributes (e.g. a relational database tuple) together with an object identifier (e.g. relational key attribute values) which are offered by the database object corresponding to the class (e.g. a relational database relation).

The attribute values corresponding to an instance are called its instance tuple, the object identifier its key value. The instance tuple of an instance may change over time, where its key value remains constant.

At definition of a db class, a mapping from instance tuples into slot values can be specified:

Within the db-connection class option a variable for each attribute of the instance tuples is declared. These attribute variables can be used occuring freely in the initforms of slots with :instance allocation. At evaluation of those initforms, they are bound to the respective values from the instance tuple.

More precisely, the evaluation of such an initform initformis, as if the following form were evaluated in the lexical environment of the def-db-class form that defined the initform:

(funcall #'(lambda (var1...varn) initform) value1...valuen)

where var1...varn are the attribute variables refered by initform and value1... valuen are the corresponding attribute values in the instance tuple.

2.6. Stored Instances of a Db Class

Storing of an instance (see section 4) means for the class to keep an association of the instances' key value to the instance.

[Generic Function]
unstore-all-instances-from-class class

This generic function effects, that all instances stored by class are unstored from class, which means that the associations (kept by the class) of key values to instances are abandoned.

Unstored instances are free to be garbage collected if there are no other references to them. Subsequent calls of the identify- functions start anew to store instances, the unstored instances then are like instances directly created by a make-instance/member[-xxx] function.

class is a db class object or a symbol that names a db class.

[Primary Method]
unstore-all-instances-from-class (class db-class) instance

This Method implements the behavior specified for the generic function.

[Primary Method]
unstore-all-instances-from-class (class symbol) instance

This method invokes unstore-all-instances-from-class on (find-class class).

2.7. The Member Classes of a Db Class

The make-member[-xxx] and identify-member[-xxx] functions create resp. identify members of a given class, i.e. instances of the class and its subclasses.

For that purpose they use the member classes of a given class: This is the set containing all classes among the given class and its subclasses whose class option abstract-member-class is false.

The class option abstractmemberclass defaults to false.

3. Relational Db Connections

3.1. Specifying Relational Db Connections

A correspondence of a db class to a relational database is defined by a db-connnection class option of the following form:

(db-connection :relational [[?relational-db-connection-argument]]) 

relational-db-connection-argument ::=
	 :db database-representative
       | :key-attributes ({key-attribute}*)
       | :attributes ({attribute-specifier}*)
       | :from ({range-variable-specifier}*)
       | :where search-condition}
       | :include-subclass-members boolean

attribute-specifier ::=
	 variable 
       | (variable column-expression [null-value-form [typespecifier]])

range-variable-specifier ::= 
         relation 
       | (relation rangevariable) 

key-attribute, column-expression, relation, range-variable and search-condition contain expressions in a database language. search-condition must be a string, the other arguments can be strings or symbols where the symbol-name is used.

For the SQL database language, the syntactical categories of the db-connection option correspond as follows (syntactical categories of SQL after [Date87]):

key-attribute ::= column-qualifier.column
column-expression ::= scalar-exp
relation ::= table
range-variable ::= range-variable
search-condition ::= search-condition

3.2. The Effective Relation

A relational db connection defined for a db class is inherited. The effective relation is the database relation effectively corresponding to a db class with relational db connection. It consists of a tuple including as subtuples 1. a key value and 2. an instance tuple for each key value for which instances of the class can be created.

The effective relation is determined by a database, a set of range variables over relations from the database, a set of attributes from them, a search condition, and a sequence of key attributes: it is the projection on the attributes and key attributes of the product of the range variables, restricted by the search condition.

Certain arguments to the relational db-connection option are given as expressions in the database language. They are concatenated by the system to larger expressions in the database language, hence they form a ``database identifier scope'' within which the ``database identifiers'' (i.e. names of relations, attributes, range variables etc.) contained in the arguments are visible to each other. Such a ``database identifier scope'' includes all the db-connection options of a db class and its superclasses.

A class whose db-connection option specifies a relational db connection must not appear together with a class whose db-connection option specifies another type of db connection in the class precedence list of any db class.

The database languages (see Database Representatives) used by all the db-connection options of the classes in any class precedence list of a db class must be the same (or at least compatible).

3.3. Inheritance of Relational Db Connections

The effective relation corresponding to a db class is determined as follows:

All the db-connection options of the class and its superclasses are ordered from most specific to least specific according to the order in the class' class precedence list.

The Database

The database representative used by the db class is the value of the :db argument in the most specific db-connection option that contains one.

It is an error if none of the db-connection options contains a :db argument. The argument of :db is a symbol that is defined as database representative (at the time of evaluation or execution of the def-db-class form).

During the evaluation of an initform and during evaluation of the argument form of a db-update slot option, the value of the *default-database-representative* variable is bound to the database representative used by the class.

The Sequence of Key Attributes

A tuple in the effective relation is uniquely identified by the values of a set of key attributes in the tuple. A set of key attributes with a total ordering on it forms the sequence of key attributes.

The sequences of key attributes, specified as lists of attribute names by the :key-attributes argument of all of the db-connection options must be ``matchable'': Their length must be the same and the respective nth attributes in each sequence must be type compatible. Since they are ``unified'' (see The Search Condition below), any one of them is good as the sequence of key attributes of the effective relation.

If none of the db-connection options contains a :key-attributes argument, the set of attributes of the effective relation with an unspecified ordering is used as sequence of key attributes.

The Set of Attributes

The set of attributes of the effective relation is the union of the sets of attributes specified by the :attributes argument in all the db-connection options.

The argument of :attributes is a list of attribute specifiers, where each attribute specifier can be a list as specified above (see section 3.1):

variable
is the attribute variable (see section 2.5) corresponding to the attribute specified by column-expression.

When forms containing attribute variables are evaluated, the attribute variables are bound to the respective database literals in their standard conversion form (see Database Representatives).

null-value-form
is a form. If in the in the instance tuple the attribute corresponding to the attribute variable has the null value, the attribute variable gets the result of evaluating null-value-form in the lexical environment of the def-db-class form that defined it as value. null-value-form defaults to the keyword symbol :null-value. null-value-form is evaluated only once during the evaluation resp. execution of the def-db-class form that defined it.

column-expression
specifies an attribute of the effective relation.

type-specifier
is a type specifier and specifies that the attribute variable will only take values of the specified type.

As short form an attribute specifier can be a single attribute variable whose symbol-name is used like the column-expression argument.

The Set of Range Variables

The set of range variables of the effective relation is the union of the set of range variables specified by the :from argument in all the db-connection options.

The argument of :from is a list of range variable specifiers, where each range variable specifier is a twoelement list containing a relation name and a range variable. The range variable then is defined to range over the relation.

As short form, a range variable specifier can be a relation name -- a range variable with the same name over the relation is defined.

The Search Condition

The membership condition of the effective relation restricts the product over the set of range variables such that it contains a single tuple for each key value for which members of the class (i.e. instances of the class or of one of its subclasses) can be created.

The membership condition is the conjunction of:

The search condition of a db-class depends on the value of :include-subclass-members in the most specific db-connection option:

4. Instance Creation and Instance Identification for Db Classes

4.1. Overview on Instance Creation and Instance Identification for Db Classes

While instance creation in pure CLOS coincides with the establishing of references to instances and is connected with the allocation of individual instances of given classes, the database correspondence of db-classes places different aspects into the foreground.

Singular Instance Creation for Given Key Values

A single db instance, corresponding to a given key value, is created by make-instance, with the key value supplied as value of the obligatory initarg db-key.

Setwise Instance Creation

A set of db instances, whose instance tuples satisfy a given database search condition, is created by make-instance-list and make-instance-lstream. make-instance-list returns an ``eager'' representation of the set as list of instances, where make-instance-lstream returns a ``lazy'' representation as ``lstream'', an object that can be manipulated analogously to Common Lisp input streams (see Database Representatives).

Instance Identification

identify-instance identifies a db instance by its class and key value: The first call of identify-instance for a given db class and key value actually creates the instance which then is stored by its class. Subsequent calls of identify-instance on the same class and key value then return the stored instance.

identify-instance can be used in place of make-instance and like an instance name. It can serve to transfer referential sharing of representations from the database into the object system and to cache db instances.

See also section 2.6.

Member Creation

make-member returns a member of a given class (i.e. an instance of that class or of a subclass of it) for a given key value.

A prerequisite for member creation is, that for no two subclasses (more precisely member classes (see section 2.7)) of the given class, instance tuples corresponding to the same key value exist.

See also section 2.7 and the description of the :include-subclass-members argument to the db-connection class option (for relational db connections).

Combinations

identify-member, identify-instance-list, identify-instance-lstream, make-member-list, make-member-lstream, identify-member-list, and identify-member-lstream combine singular instance creation for given key values, setwise instance creation, instance identification and member creation.

The setwise identify- functions can be used to ``load'' instances which may be used afterwards by the application.

The setwise -member- functions return the union of instances of the given class and its relevant subclasses (the given class' member classes) whose instance tuples satisfy the search condition.

4.2. Functions for Singular Instance Creation and Instance Identification

[Primary Method]

make-instance
        (class db-class) &rest initargs &key db-key 

When called by programs, the db-key initarg, which specifies a key value, must be supplied. An instance tuple corresponding to the key value and the class' db connection is retrieved and a new instance of the class for the instance tuple is created and returned. The new instance is created by calling the next method make-instance (standard-class) on class, initargs and further implementation specific initargs.

db-key
is an object that identifies a key value.

For a classes with relational db connection db-key can be a list of objects or a single object which matches with the class' sequence of key attributes: If db-key is a cons, it must have the same length as the sequence of key attributes. If there is only a single key attribute, db-key can be a single object (an atom) corresponding to that attribute. The db-literal function, called on the nth element of the list (resp. on the single object) must yield a print representation of a proper value for the nth (resp. single) key attribute.

When the retrieval of the instance tuple fails because no instance tuple corresponding to db-key and the class' db connection exists, no-instance-tuple is invoked as follows:

(apply #'no-instance-tuple class 'nil 'make-instance initargs)

Functions for instance creation and identification which are implemented using make-instance may call make-instance on implementation specific initargs. When certain such initargs are supplied, this method immediately invokes the next method (usually make-instance (standard-class)) on the original arguments.

[Generic Function]

identify-instance
        class &rest initargs &key db-key &allow-other-keys

When called by programs, the db-key initarg, which specifies a key value, must be supplied.

If the class does not already store an instance for the key value, make-instance is called on the original arguments. When make-instance returns an instance of the class, the instance is stored by the class for the key value. The values returned by make-instance are returned.

If the class already stores an instance for the key value, then, if the class is a live db class and the instances' existence is valid or the class is a snapshot db class, reinitialize-stored-instance is called on the instance and initargs and the instance is returned.

If the class is a live db class and the stored instances' existence is invalid, reinitialize-stored-instance is called on an instance as described in section 6.4 and initargs and that instance is returned. The identification of such an instance may fail because the instance tuple corresponding to the key value does not exist in the database. In this case no-instance-tuple is invoked as follows (where instance is the stored instance with invalid existence):

(apply #'no-instance-tuple class instance 'identify-instance initargs)

The arguments of identify-instance are identical to those of make-instance.

Functions which are implemented using identify-instance may call identify-instance with implementation specific initargs, such that when these are passed to make-instance, make-instance (db-class) immediately calls the next method.

[Generic Function]

make-member
        class &rest initargs &key db-key &allow-other-keys

The db-key initarg, which specifies a key value, must be supplied.

Until it succeeds, this generic function attempts for each class among the member classes of the given class to retrieve an instance tuple which corresponds to the key value and the respective member class' db connection. A new instance is created by calling make-instance on the member class for which the instance tuple has been retrieved, initargs and implementation specific initargs (such that make-instance (db-cl ass) immediately calls the next method). The value of make-instance (the newly created instance) is returned.

The arguments of make-member are identical to those of make-instance.

If for none of the member classes an instance tuple can be retrieved, no-instance-tuple is invoked as follows:

(apply #'no-instance-tuple class 'nil 'make-member initargs)

[Generic Function]

identify-member
        class &rest initargs &key db-key &allow-other-keys

This generic function combines identify-instance and make-member.

The db-key initarg, which specifies a key value, must be supplied.

identify-member proceeds as follows:

If one of the class' member classes stores an instance (if the class is a live db class: with valid existence or with invalid existence but with its instance tuple existing in the database. In the latter case the stored instance with invalid existence is replaced by an instance as described in section 6.4.) for the key value, reinitializ-estored-instance is called on the instance and initargs and the instance is returned.

Otherwise, until it succeeds, identify-member attempts for each class among the member classes of the given class to retrieve an instance tuple which corresponds to the key value and the respective member class' db connection. A new instance is created by calling make-instance on the member class for which the instance tuple has been retrieved, initargs and implementation specific initargs (such that make-instance (db-class) immediately calls the next method). The newly created instance is stored by its class for the key value and returned.

The arguments of identify-member are identical to those of make-instance.

If (after no stored instance has been found) for none of the member classes an instance tuple can be retrieved, no-instance-tuple is invoked as follows:

(apply #'no-instance-tuple class 'nil 'identify-member initargs)

4.3. Functions for Setwise Instance Creation and Instance Identification

[Generic Function]

make-instance-list
        class &key :db-cond :order-by :max-no-of-elements :initargs

For each instance tuple corresponding to the class' db connection that satisfies the search condition :db-cond, this generic function creates a new instance by calling make-instance on the class, :initargs and implementation specific initargs (such that make-instance (db-class) immediately calls the next method).

A list that contains the newly created instances is constructed and returned.

class
is a class object or a symbol that names a class.

:db-cond
is a search condition in the database language or nil.

A search condition can be given as a string or a nonempty list. If it is a list, a string is used, which is obtained from the list in the same way as described for the query argument of the db-query-xxx functions (see Database Representatives). If :db-cond is nil, no search condition (i.e. a ``true'' search condition) is used.

:db-cond defaults to nil.

The search condition is included into the ``database identifier scope'' of the class' db connection.

For a relational db connection that uses the SQL database language, the search condition has the syntactical category (after [Date87]) search-condition.

:order-by
is an ordering specification in the database language or nil.

An ordering specification can be given as a string or a nonempty list. If it is a list, a string is used, which is obtained from the list in the same way as described for the query argument of the db-query-xxx functions (see Database Representatives). If :order-by is an ordering specification, the instances are returned in the specified ordering. If :order-by is nil, the instances are returned in an arbitrary ordering.

:order-by defaults to nil.

The ordering specification is included into the ``database identifier scope'' of the class' db connection.

For a relational db connection that uses the SQL database language, the ordering specifier has the syntactical category (after [Date87]) ordering-spec-commalist.

:max-no-of-elements
can be nil or an integer >= 0.

If :max-no-of-elements is an integer, at most :max-no-of-elements of the instance tuples satisfying the search condition are considered.

If :max-no-of-elements is nil, all instance tuples satisfying the search condition are considered.

:max-no-of-elements defaults to nil.

[Generic Function]

make-instance-lstream
        class &key :db-cond :order-by :buffering :initargs

This generic function behaves like make-instance-list, except that it constructs and returns an lstream containing the instances instead of a list.

The arguments of make-instance-lstream are identical to those of make-instance-list, with exception of :max-no-of-elements and :buffering.

:buffering
can be nil or an integer > 0.

If :buffering is an integer the system tries to actually produce the elements of the lstream chunks of :buffering elements, which can improve performance.

:buffering defaults to nil.

[Generic Function]

identify-instance-list
        class &key :db-cond :order-by :max-no-of-elements :initargs

This generic function behaves like make-instance-list, except that instead of creating an instance, it identifies an instance by calling identify-instance on the class, :initargs and implementation specific initargs (such that make-instance (db-class), when called by identify-instance, immediately calls the next method) for each instance tuple satisfying the search condition.

The arguments of identify-instance-list are identical to those of make-instance-list.

[Generic Function]

identify-instance-lstream
        class &key :db-cond :order-by :buffering :initargs 

This generic function behaves like identify-instance-list, except that it constructs and returns an lstream containing the instances instead of a list.

The arguments of identify-instance-lstream are identical to those of make-instance-lstream.

[Generic Function]

make-member-list
        class &key :db-cond :order-by :max-no-of-elements :initargs 

This generic function constructs and returns a list of instances by concatenating the results of calling make-instance-list on each member class of class and :initargs where the :max-no-of-elements initarg (if it is an integer) is decremented after each call to make-instance-list by the number of actually created instances.

The arguments of make-member-list are identical to those of make-instance-list.

[Generic Function]

make-member-lstream
        class &key :db-cond :order-by :buffering :initargs 

This generic function behaves analogous to make-member-list, except that it constructs and returns an lstream containing the instances.

The resulting lstream gets its elements from ``sublstreams'' which are constructed by calling make-instance-lstream on the member classes of class and :initargs. Until there are no more member classes, at retrieval of an element from the resulting lstream a new sub-lstream is constructed at the first retrieval and whenever the previously constructed sub-lstream is exhausted.

The arguments of make-member-lstream are identical to those of make-instance-lstream.

[Generic Function]

identify-member-list
        class &key :db-cond :order-by :max-no-of-elements :initargs 

This generic function behaves like make-member-list, except that it calls identify-instance-list instead of make-instance-list on each member class of class and :initargs (with :max-no-of-elements appropriately decremented).

The arguments of identify-member-list are identical to those of make-instance-list.

[Generic Function]

identify-member-lstream
	class &key :db-cond :order-by :buffering :initargs 

This generic function behaves like make-member-lstream, except that the elements of the resulting lstream are obtained by calling identify-instancelstream on the member classes and :initargs instead of make-instance-lstream.

The arguments of make-member-lstream are identical to those of make-instance-lstream.

4.4. Method Signatures of Methods for Instance Creation and Instance Identification

The following methods implement the specified behaviors of their generic functions. Methods, whose class argument is specialized on symbol invoke their generic function on (find-class class) and initargs resp. args.

[Primary Method]

identify-instance
        (class live-db-class) &rest initargs &key db-key

[Primary Method]

identify-instance
        (class snapshot-db-class) &rest initargs &key db-key
[Primary Method]
identify-instance
        (class symbol) &rest initargs
[Primary Method]
make-member
        (class db-class) &rest initargs &key db-key
[Primary Method]
make-member
        (class symbol) &rest initargs
[Primary Method]
identify-member
        (class live-db-class) &rest initargs &key db-key
[Primary Method]
identify-member
        (class snapshot-db-class) &rest initargs &key db-key
[Primary Method]
identify-member
        (class symbol) &rest initargs
[Primary Method]
make-instance-list
        (class db-class) 
        &key :db-cond :order-by :max-no-of-elements :initargs
[Primary Method]
make-instance-list
        (class symbol) &rest args
[Primary Method]
make-instance-lstream
        (class db-class)
        &key :db-cond :order-by :buffering
[Primary Method]
make-instance-lstream
        (class db-class) &rest args

For each of the other generic functions for setwise instance/member creation/identification there are methods with the same signature as specified above for make-instance-list and make-instance-lstream respectively.

4.5. Reinitialization at Instance Identification

[Generic Function]
reinitialize-stored-instance instance &rest initargs

This generic function is called by identify-instance and identify-member to reinitialize stored instances.

instance
is the object to be initialized.

initargs
consists of alternating initialization argument names and values.

The value returned by reinitialize-stored-instance is ignored.

[Primary Method]
reinitialize-stored-instance (instance db-object) &rest initargs

This method calls reinitialize-instance on instance and initargs. Programs can override this method.

4.6. Handler Functions

[Generic Function]
no-instance-tuple class instance situation &rest args

This generic function may be called during evaluation of make-instance, identify-instance, make-member, identify-member, slot-value and shared-initialize.

The values returned by methods for this function get returned as the values of the original function invocation.

[Primary Method]
no-instance-tuple (class t) (instance t) (situation t) &rest args

This method signals an error.

5. Associating Database Updates with Live Db Instances

5.1. Specifying Slots with associated Database Updates

The db-update slot option for live db classes allows specify database updates to be associated with the slot.

The database updates associated with a slot are determined by the argument of the db-update slot option in the most specific slot specifier for that slot that contains one:

If this argument is nil or if no slot specifier contains a db-update slot option, no database updates are associated with the slot.

Otherwise, if the argument is a non-nil form, whenever the slot is written (unless due to the initializion according to its initform) the database is updated (after the new slot value is stored) in the following way: The argument of the db-update slot option is evaluated analogously to initforms with proper attribute variables (see below) in the lexical environment of the def-db-class form that defined it. The value obtained, which must be a four-place function, is called on the slot value of the slot, the class of the instance, the instance and the effective slot-definition metaobject corresponding to the slot.

Remark: It is not specified, when the values of the attribute variables used for evaluating the argument form of a db-update slot option are retrieved from the database. However, this should not be a problem: The intendend purpose of attribute variables in the slot option is to manage relationships represented in relations that use alternate keys [Date90] instead of the key attributes specified for the effective relation of some given class. The values of attribute variables containing an alternate key to the effective relation never change for a given instance.

5.2. Functions for Use in the db-update Slot Option

[Function]
update-attributes &key :attributes :relation :where :db

This function is intended to be used within the db-update slot option of db classes with relational db connection.

It returns a four-place function with the parameters: new-value class instance slot.

The arguments of update-attibutes are a set of attributes, a relation, a search condition and a database-representative.

The function returned by update-attributes defaults these arguments and effects that in the tuples from the relation which satisfy the search condition the attributes are updated to the values specified by the new-value argument.

:attributes
is a single attribute specifier in the database language or a list of such attribute specifiers, where an attribute specifier can be given as a string or a symbol (in the latter case the symbol-name is used).

The specified attributes must be from the relation specified by :relation.

If :attributes is a nonempty list, new-value must be a list with the same length. The new value of the nth attribute is the results of calling db-literal on the nth element of new-value (and the database-representative-language of the database-representative specified by :db). If :attributes is an non-nil atom, new-value must be a single object, db-literal called on the object (and, as above, the database-representative-language) is the new value of the attribute.

If :attributes is the empty list or unspecified, no database updates are effected by the function resulting from update-attributes.

:relation
is a relation specifier in the database language and can be given as string or symbol, where the symbol-name is used.

:relation defaults to the relation specified as :from argument of the db-connection option of the class, that defines the db-update slot option. If :from doesn't specify a single relation, :relation has to be supplied.

:where
is a search condition in the database language, given as a string, that restricts the specified relation.

:where defaults to a search condition, that equates the key attributes specified by the :key-attributes argument of the db-connection option of the class, that defines the db-update slot option, with the key values of the instance (only the attribute names of the attributes specified as :key-attributes are used, not their qualifying range variables). If :key-attributes is unspecified :where has to be supplied.

:db
is a symbol that is defined as a database-representative and specifies the database on which the relation is updated.

:db defaults to the database-representative usesd for the effective relation of class.

For the SQL database language the syntactical categories (after [Date87]) of specifiers in the database language are as follows: relation specifier: table, attribute specifier: column, search condition: search-condition.

[Function]
adjust-relation &key :attributes :relation :self-key-attributes :self-key-values :db

This function is intended to be used within the db-update slot option of db classes with relational db connection. It can serve to map a slot representing a set into a database relation.

It returns a four-place function with the parameters: new-values class instance slot.

The arguments of adjust-relation are a set of attributes, a relation, a set of attributes called self-key attributes, a set of values for them called self-key values and a database-representative.

The function returned by adjust-relation defaults these arguments and effects that the relation is modified by deleting the additional tuples from the relation and afterwards inserting the missing tuples into the relation (attributes of the relation not included in the set of arguments get the null value), where:

:attributes
is a single attribute specifier in the database language or a list of such attribute specifiers, where an attribute specifier can be given as a string or a symbol (in the latter case the symbol-name is used).

The specified attributes must be from the relation specified by :relation.

If :attributes is a nonempty list, new-values must be a list of sublists with the same length as :attributes. The values used for comparing with database literals and inserting into the database for the nth attribute are the results of calling db-literal on the respective nth element in a sublist (and the database-representative-language of the database-representative specified by :db).

If :attributes is an non-nil atom, new-values must be a list of single objects, the results of calling db-literal on each of these objects (and, as above, the database-representative-language) are used for comparing and inserting.

If :attributes is the empty list or unspecified, no database updates are effected by the function resulting from adjust-relation.

:relation
is a relation specifier in the database language and can be given as string or symbol, where the symbol-name is used.

:relation must be supplied.

:self-key-attributes
is a single attribute specifier in the database language or a nonempty list of such attribute specifiers, where an attribute specifier can be given as a string or a symbol (in the latter case the symbol-name is used).

The specified attributes must be from the relation specified by :relation.

:self-key-attributes defaults to the key attributes specified by the :key-attributes argument of the db-connection option of the class, that defines the db-update slot option (as list of attribute specifiers, where only the attribute names of the attributes specified as :key-attributes are used, not their qualifying range variables). If :key-attributes is unspecified :self-key-attributes has to be supplied.

:self-key-values
is a single object or a list of objects according to whether :self-key-attributes is a single attribute specifier or a list of attribute specifiers.

The values used for comparing with database literals and inserting into the database for the single (resp. nth) self-key attribute are obtained by calling db-literal on :self-key-values (resp. the nth element of :self-key-values) (and the database-representative-language of the database-representative specified by :db).

:self-key-values defaults to the key value (as a list of objects) of the instance.

:db
is a symbol that is defined as a database-representative and specifies the database on which the relation is updated.

:db defaults to the database-representative usesd for the effective relation of class.

For the SQL database language the syntactical categories (after [Date87]) of specifiers in the database language are as follows: relation specifier: table, attribute specifier: column.

[Function]
adjust-relation-update-insert-nullify &key :attributes :relation :self-key-attributes :self-key-values :db

This function is similar to the adjust-relation function, except that:

The values of the self-key attributes of tuples with the same values for the attributes as a missing tuple are set to the self-key values.

6. Invalidation of Existences and Slots of Live Db Instances

6.1. Specifying Invalidateable Slots

Invalidateable slots actually combine two concepts: instantiation of the components of composite objects on demand and re-retrieval of information from the database.

Slots of live db instances with allocation :instance can be invalidateable.

Whether a slot is invalidateable is controlled by the most specific slot specifier for the slot:

6.2. Accessing Invalidateable Slots

An invalidateable slot at any point of time is either valid which means that it stores its actual value, or invalid which means that it stores no value or an obsolete value.

An invalid slot with an initform appears as bound to the result of evaluating its initform anew. At reading, the slot is validated: its initform is evaluated and stored. At the evaluation of the initform it is ensured, that the values of the attribute variables occuring in the initform were retrieved from the database after the invalidation of the slot.

An invalid slot without an initform appears as unbound.

A valid slot is accessed as usual.

Writing an invalid slot makes it valid.

6.3. Initialization of Invalidateable Slots

shared-initialize does not initialize any invalidateable slots indicated by the slotnames argument according to their initforms. These slots initially are invalid.

6.4. Invalidation of Instance Existences

A live db instance must have a corresponding tuple in the database, tuples however can be deleted.

Invalidating all slots of an instance implicitely (i.e. by make-invalid called on a slotset argument obtained by calling slotset on :all-slots or on another keyword with t as slotnames argument) invalidates the so-called existence of the instance.

Live db instances with invalid existence must not be used. If there is a stored (see section 4.1) instance with invalid existence for a given class and key-value, the identify- functions however return and store an instance (which may be identical (eq) to the instance with invalid existence or not) whose non-invalidateable slots take over the values from the instance with invalid existence.

At the creation of an instance it is ensured, that a corresponding instance tuple exists in the database. The functions for instance creation and identification never return instances with invalid existence.

6.5. Failure of Revalidation at Reading a Slot Value

If the revalidation of a slot (entailed by a call to slot-value) fails because because the instance's instance tuple no longer exists in the database (this might happen if the database has changed without a corresponding invalidation of the live db instances), the handler generic function no-instance-tuple is called as follows:

(no-instance-tuple (classof object) object 'slot-value slot-name)

6.6. Making Slots Invalid

[Function]
make-invalid &optional slotset

This function effects that existences or the invalidateable slots in the set of slots specified by slotset become invalid as described in section 6.4.

slotset
is a slotset object as described in section 6.7. It defaults to a slotset object obtained by (slotset :all-slots).

6.7. Specifying Sets of Slots

[Function]
slotset keyword &rest args

This function returns a slotset object, an object which specifies a set of slots. The make-invalid generic function takes such an object as argument.

The set of slots specified by the slotset is determined by the keyword argument (which is a keyword symbol) and, depending on keyword, further arguments. The following arguments are accepted:

:all-slots
The slotset specifies the set of all slots.

:slots-of-instances-of-class class [slot-names]
class is a class object or a symbol that names a class.

slot-names is a list of slot names or the symbol t, which is the default value and indicates all slots.

The slotset specifies the set of all slots indicated by slot-names of all instances of the class.

:slots-of-instances instances [slot-names]
instances is a single instance or a (possibly empty) list of instances.

slot-names is a list of slot names or the symbol t, which is the default value and indicates all slots.

The slotset specifies the set of slots indicated by slot-names of the instances.

:slots instance-slotname-pairs
instance-slotname-pairs is a list of dotted pairs: the car of each pair is an instance, the cdr a slot name.

The slotset specifies the set of slots which contains for each instance-slotname pair the respective slot of the instance.

7. Database Transactions

[Function]
single-db-user

[Function]
(setf single-db-user) new-value

These functions maintain a flag that indicates whether the database is used by multiple users or exclusively by the Lisp session.

single-db-user returns the value of the flag, (setf single-db-user) assigns new-value as the value of the flag.

The default setting of the flag is false.

If the flag is set from true to false, db-rollback is called (after the flag has received its new value). The behavior of the db-commit and db-rollback functions depends on the value of single-db-user (see below).

[Standard Class]
clos-db-setup

The default value of the *setup* variable (after loading CLOS-DB) is an instance of clos-db-setup.

clos-db-setup is a subclass of database-representatives-setup. Programs may create subclasses of clos-db-setup and bind *setup* to it. The results are undefined if programs override any methods specified in this document which specialize on clos-db-setup.

The following methods extend the behavior of the db-commit, db-rollback, open-database-representative and close-database-representative functions specified in Database Representatives:

[After Method]
db-commit-using-setup (setup clos-db-setup)

If the single-db-user flag is false, this method calls make-invalid on a slotset object obtained by (slotset :all-slots).

The results are undefined if afterwards elements are retrieved from lstreams previously returned by a function specified in this document or in Database Representatives.

[After Method]
db-rollback-using-setup (setup clos-db-setup) &rest args

If the single-db-user flag is false, this method calls make-invalid on a slotset object obtained by (slotset :all-slots).

The results are undefined if afterwards elements are retrieved from lstreams previously returned by a function specified in this document or in Database Representatives.

[Before Method]
close-database-representative-using-setup (setup clos-db-setup) database-representative &key :abort

Unless the database representative is already closed this method calls make-invalid on a slotset object obtained by (slotset :all-slots).

The results are undefined if afterwards elements are retrieved from lstreams connected to the database representative (i.e. lstreams that may contain instances of classes which uses the database representative for their effective relation) which were previously returned by a function specified in this document or in Database Representatives.

8. References

[AMOP]
G. Kiczales, J. des Rivieres, D.G. Bobrow: The Art of The Metaobject Protocol, Chapters 5 and 6. MIT Press, Cambridge, Massachusetts, 1991.

[Date87]
C.J. Date: A Guide to the SQL Standard, Appendix B. AddisonWesley, Reading, Massachusetts, 1987.

[Date90]
C.J. Date: An Introduction to Database Systems, Volume 1, Fifth Edition. Addison-Wesley, Reading, Massachusetts, 1990

9. Index of Functions, Macros, Classes, Class Options and Slot Options

This index also includes methods presented apart from their generic function specification.

abstract-member-class class option
adjust-relation function
adjust-relation-update-insert-nullify function
clos-db-setup standard class
close-database-representative-using-setup (clos-db-setup) before method
db-class metaclass
db-commit-using-setup (clos-db-setup) before method
db-connection class option
db-object standard class
db-rollback-using-setup (clos-db-setup) before method
db-update slot option
def-db-class macro
identify-instance generic function
identify-instance-list generic function
identify-instance-lstream generic function
identify-member generic function
identify-member-list generic function
identify-member-lstream generic function
invalidateable slot option
live-db-class metaclass
live-db-object standard class
make-instance (class db-class) primary method
make-instance-list generic function
make-instance-lstream generic function
make-invalid function
make-member generic function
make-member-list generic function
make-member-lstream generic function
no-instance-tuple generic function
reinitialize-stored-instance generic function
(setf single-db-user) function
single-db-user function
slotset function
snapshot-db-class metaclass
snapshot-db-object standard class
unstore-all-instances-from-class generic function
update-attributes function