[ Table Of Contents | Keyword Index ]

relvar(n) 0.12.2 ral "Relvar Operators"

Name

relvar - Operators for Relation Variables

Table Of Contents

Synopsis

  • package require ral ?0.12.2?

Description

This manpage describes the relvar command. The relvar command is part of the Tcl Relational Algebra Library (ral) package.

TclRAL defines a variable space for relation variables. Relation variables hold relation values and the subcommands of the relvar command generally operate directly on the values storing the results back into the relation variables. For this reason, most of the relvar subcommands take the name of a relation variable as an argument.

In the relational model as it applies to database management systems, relation variables play the important role of representing the persistent data base values. Relation variables are the leaves of the expression tree for a query and represent the core data from which results may be computed. That computation is usually expressed as a single, sometimes complex expression. This allows for a non-procedural way of specifying the computation and allows optimizers to find the most efficient manner of computing the result.

In the TclRAL implementation of the relational model, relation variables serve a similar role although there is no implicit persistence supplied by the library. Relation values may be stored in Tcl variables like any other Tcl object. This does abandon the non-procedural nature of relational expressions as usually accomplished in the relational model, but is a better fit to the Tcl way of doing things.

RELVAR NAMES

Relvar names follow the familiar Tcl method of naming ordinary Tcl variables and thus relvars have Tcl namespace-like names. For example, a relvar named Dog created at the global level will be named ::Dog. However, relvars names are held separately from Tcl variable names and despite the similar syntax and appearance, relvars are a concept only of TclRAL. Thus it is possible and indeed encouraged to group related relvars together in a namespace. If an application uses only one set of relvars, then the global namespace of relvars is most convenient. Using several distinct sets of relvars is best accomplished if each set is placed in their own relvar namespace.

Since it is possible to store a relation value in an ordinary Tcl variable and since Tcl variables are convenient to use when formulating relational expressions (i.e. it is sometimes more convenient to say $Dog rather than [relvar set Dog]), creating a relvar also creates a corresponding Tcl variable by the same name. The Tcl variable created is traced to prevent accidental writing to it, since all modifications to a relvar should come via the relvar commands. So, creating a relvar named Dog at the global level creates a relvar named ::Dog and a read-only Tcl variable also named ::Dog. However, it should be noted that the automatically created Tcl variable is not protected against unset. It is allowed to unset the Tcl variable and still access the relation value stored in the relvar.

CONSTRAINTS

TclRAL supports the notion of constraints as a means of insuring integrity among a set of relvars. There are many types of constraints that might be used to insure integrity, but TclRAL supports three distinct types of constraints: identification constraints, referential constraints and procedural constraints.

Identification

Identification constraints define a set of attributes that must have unique values. Each relvar must specify at least one identifier. An identifier is one or more attributes whose values taken together must be unique for all tuples stored in the relvar. Identifiers must also be minimal in the sense that no two identifiers for a given relvar are allowed to be a subset of one another.

Referential

Referential constraints define how tuples of one relvar refer to tuples in another relvar.

Procedural

Procedural constraints define a Tcl script that is evaluated to determine if the constraint is satisfied.

Identification constraints are enforced on a relvar by any operation that modifies the relation value stored in the relvar. For referential types of constraints three forms are supported.

Association

Association constraints define a referential association between two relvars. In this context, an association declares that a set of attributes in one relvar refers to an identifier of another relvar. Thus for all the tuples in a given relvar, the given attribute values must match the corresponding attribute values of the identifier of the associated relvar. The association also declares the number of times that such matches may occur and if it is allowed not to match at all.

Partition

Partition constraints define a complete and disjoint referential partitioning between one relvar, known as the super set, and a given set of relvars, known as the sub sets. This constraint declares that every tuple of the super set relvar is referred to by exactly one tuple from among all the tuples in the sub set relvars.

Correlation

Correlation constraints define a referential association between two relvars that is mediated by a third relvar. The third relvar, the correlation relvar, contains attributes that reference identifiers in the two associated relvars. It is similar in some ways to two Association Constraints.

Procedural constraints are enforced by evaluating a Tcl script when a given set of relvars are modified. At the end of each ::ral::eval command or after a ::ral::transaction end command(see below) or, if outside of an eval command, at the end of any command that modifies a relvar that participates in a referential constraint, all of the referential and procedural constraints defined for the modified relvars are evaluated. If any of the constraints fail, the relvar modifications are discarded and the relvar values are returned to the values they had before the modifications. Similarly, during the creation of a constraint, the constraint is evaluated on all the relvars associated with the constraint. If the evaluation fails, the constraint creation fails. Like relvars, constraints have names. Constraints names follow the same pattern as relvar names, i.e. unresolved names are created in the current namespace. Thus you are able to keep the relvars and their constraints organized together in namespace-like groups.

COMMANDS

::ral::relvar association name refrngRelvar refrngAttrList refToSpec refToRelvar refToAttrList refrngSpec

The association subcommand creates a referential association between two relvars called name. The return value of association is the empty string. Associations declare that one relvar has attributes that refer to an identifier of another relvar. The referring relvar name is given by the refrngRelvar argument and the referring attributes are given by refrngAttrList argument. The referred to relvar name is given by refToRelvar and the attributes that are referred to by refToAttrList. The referring and referred to attribute lists are ordered and referring attributes refer to the corresponding referred to attribute. The set of attributes given by refToAttrList must constitute an identifier for refToRelvar. The refToSpec argument defines the multiplicity and conditionality of the reference. It can be one of:

*

Each tuple in refToRelvar is referred to zero or more times by the tuples in refrngRelvar.

+

Each tuple in refToRelvar is referred to one or more times by the tuples in refrngRelvar.

1

Each tuple in refToRelvar is referred to exactly once by the tuples in refrngRelvar.

?

Each tuple in refToRelvar is referred to zero or one times by the tuples in refrngRelvar.

Similarly refrngSpec defines the multiplicity and conditionality associated with the references to refToRelvar. Necessarily, refrngSpec may only be "1" or "?" implying:

1

Each tuple in refrngRelvar refers to exactly one tuple in refToRelvar.

?

Each tuple in refrngRelvar refers to at most one tuple (and possibly none at all) in refToRelvar.

The symbols for refrngSpec and refToSpec were chosen by analogy to the use of those symbols in regular expression syntax.

% relvar association A1 OWNERSHIP OwnerName + OWNER OwnerName 1
% relvar association A2 OWNERSHIP DogName * DOG DogName 1

In this example, A1 declares that for every tuple in OWNERSHIP, the value of OWNERSHIP.OwnerName matches the value of OWNER.OwnerName in exactly one tuple of OWNER and that for every tuple in OWNER the value of OWNER.OwnerName matches the value of OWNERSHIP.OwnerName in at least one tuple of OWNERSHIP and possibly more. In the semantics of this example, the concepts of being an OWNER and that of OWNERSHIP of a DOG are unconditionally associated since no tuple of OWNER may exist without there being at least one associated tuple of OWNERSHIP. Also this constraint allows for OWNERS that may own more than one DOG. Compare this to the case of A2. A2 states that every tuple in OWNERSHIP must have a corresponding tuple in DOG, but that tuples in DOG may not be referenced by any tuple in OWNERSHIP. OWNERSHIP and DOG are conditionally associated and in the semantics of this problem, it is possible to have dogs that are not owned at all and to have dogs that are owned multiple times.

::ral::relvar constraint delete ?name1 name2 ...?

The constraint delete subcommand deletes all the constraints given by the nameN arguments. The return value is the empty string.

::ral::relvar constraint exists name

The constraint exists subcommand returns a boolean value of true if the relvar named name exists and false otherwise. The relvar name argument is resolved according to the rules described above.

::ral::relvar constraint info name

The constraint info subcommand returns the detailed information about the constraint named name. The information returned is of the same format as the command used to create the constraint minus the superfluous leading relvar command word. Additionally, the relvar names and constraint names are returned in fully qualified form.

% relvar constraint info A1
association ::A1 ::OWNERSHIP OwnerName + ::OWNER OwnerName 1
% relvar constraint info ::P1
partition ::P1 ::Lamp SerialNo ::TableLamp SerialNo ::FloorLamp SerialNo
% relvar constraint info G
unknown constraint name, "G"
::ral::relvar constraint names ?pattern?

The constraint names subcommand returns a list of constraint names. If the optional pattern is present, then only those constraint names that match pattern are returned. Name matching happens in the same manner as for the string match. The returned names are fully qualified.

% relvar constraint names
::A1 ::A2
% relvar constraint names *2
::A2
::ral::relvar constraint member relvarName

The constraint member subcommand returns a list of constraint names in which relvarName participates in some fashion. The returned names are fully qualified.

% relvar constraint member OWNERSHIP
::A1 ::A2
::ral::relvar constraint path constraintName

The constraint path subcommand returns the fully qualified constraint name of constraintName.

::ral::relvar correlation ?-complete? name correlRelvar correlAttrListA refToSpecA refToRelvarA refToAttrListA correlAttrListB refToSpecB refToRelvarB refToAttrListB

The correlation subcommand creates a referential correlation called name. The referential correlation is between a correlation relvar, correlRelvar, and two other relvars, refToRelvarA and refToRelvarB. The return value of the correlation command is the empty string. Correlations declare that every tuple in correlRelvar refers to exactly one tuple of refToRelvarA and exactly one tuple of refToRelvarB. The correlAttrListA attributes in correlRelvar refer to an identifier of refToRelvarA that is given by the attributes contained in the refToAttrListA list. Similarly, the correlAttrListB attributes in correlRelvar refer to an identifier of refToRelvarB that is given by refToAttrListB. Both refToAttrListA and refToAttrListB must constitute an identifier for their corresponding relvars. The refToSpecA and refToSpecB arguments can have the same values as for the ::ral::relvar association command and specify the multiplicity and conditionality of how refToRelvarA and refToRelvarB are referred to by the tuples of correlRelvar. If the -complete option is given, then every tuple of refToRelvarA must be correlated to every tuple of refToRelvarB and vice versa. The -complete option implies the cardinality of correlRelvar must equal the product of the cardinality of refToRelvarA and refToRelvarB. If the -complete option is missing, then correlRelvar is allowed to have a subset of the Cartesian product of the references.

Correlation constraints are often used to enforce the referential constraints for relvars that are related in a many to many fashion. However, they also arise in situations where the multiplicity is not many-to-many but when the correlRelvar contains attributes that apply to the association between refToRelvarA and refToRelvarB themselves.

% relvar correlation C1 OWNERSHIP OwnerName + OWNER OwnerName DogName * DOG DogName
::ral::relvar create relvarName heading id1 ?id2 ...?

The create subcommand creates a new relation variable whose name is given by relvarName and that will store a relation value whose heading matches that of the heading argument. The heading argument is a list with an even number of elements consisting of alternating attribute names and attribute data types as described for the ::ral::relation command. The tuples of the relation value will be identified by id1 and any other supplied idN arguments. Each idN argument is a list of attribute names that appear in the heading. The subcommand returns the relation value of the newly created relvar, which necessarily will have cardinality of 0. If relvarName name begins with "::", then it is interpreted as a fully resolved name and will be created in the given namespace. Otherwise, relvarName is interpreted as relative the to current namespace. In either case, an ordinary Tcl variable is also created by the same fully resolved name as the relvar. This implies that any namespaces referenced in relvarName must already exist.

% relvar create OWNER {OwnerName string Age int City string} OwnerName
{OwnerName string Age int City string} {}
% puts [relformat $::OWNER]
+---------+---+------+
|OwnerName|Age|City  |
|string   |int|string|
+---------+---+------+
+---------+---+------+
% relvar create DOG {DogName string Breed string} DogName
{DogName string Breed string} {}
% relvar create OWNERSHIP {OwnerName string DogName string Acquired string} {OwnerName DogName}
{OwnerName string DogName string Acquired string} {}
::ral::relvar delete relvarName tupleVarName expression

The delete subcommands deletes tuples from the relation variable given by the relvarName argument. Each tuple in the body of relvarName is successively assigned to the tuple variable named tupleVarName and expression is evaluated. If expression returns true, then that tuple is deleted, directly modifying the value contained in relvarName. The return value of the subcommand is the number of tuples deleted.

% puts [relformat $::OWNER "Before deleting Sue"]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
Before deleting Sue
-------------------
% relvar delete OWNER o {[tuple extract $o OwnerName] eq "Sue"}
1
% puts [relformat $::OWNER "After deleting Sue"]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
After deleting Sue
------------------
::ral::relvar deleteone relvarName ?attr1 value1 attr2 value2 ...?

The deleteone subcommand deletes at most one tuple from the relation variable given by the relvarName argument. The attrN valueN arguments must be given in pairs and are the attribute names and values that determine which tuple is deleted from the relation value held in relvarName. The set of attribute names in the attrN valueN arguments must form one of the identifiers of relvarName. If relvarName contains a tuple whose attribute values match those in given then that tuple is deleted and relvarName is modified in place. Otherwise relvarName is unchanged. This subcommand is useful in those contexts where the attribute values of an identifier are known and evaluating an expression over all the tuples in relvarName is superfluous. The return value of the subcommand is the number of tuples deleted which will necessarily be either 1 or 0.

% puts [relformat $::OWNER "Before deleting Mike"]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
Before deleting Mike
--------------------
% relvar deleteone OWNER OwnerName Mike
1
% puts [relformat $::OWNER "After deleting Mike"]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
After deleting Mike
-------------------
% relvar deleteone OWNER OwnerName Alfonse
0
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
::ral::relvar dunion relvarName ?relationValue1 ...?

The dunion subcommand performs the relation disjoint union of the relation value contained in relvarName with the given relationValueN arguments and assigns the result back into relvarName. This command is shorthand for:

relvar set <relvarName> [relation dunion [relvar set <relvarName>] <relationValue1> ...]

The headings of each relationValueN must match that of the value contained in relvarName. Any duplicated tuples will cause an error to be thrown and thus this command has insert type semantics. Since the disjoint union operation is commutative, the order of the relationValueN arguments does not affect the result. The return value of the command is the new relation value stored in relvarName.

::ral::relvar eval arg ?arg ...?

The eval subcommand concatenates it arguments together and evaluates the resulting script as a relvar transaction. The return value of eval is the return value of the last command executed in the script. At the end of the script, the constraints associated with any relvar that was modified by the script are evaluated. If either the script generates an error or any of the constraints fail, then the values of the modified relvars are returned to the values they held before the eval command. It is an error to attempt to create relvars or constraints in the script executed by eval.

% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar eval {
>       relvar insert OWNER {OwnerName Tom Age 22 City Tulsa}
> }
for association ::A1(::OWNERSHIP [+] ==> [1] ::OWNER), in relvar ::OWNER
tuple {OwnerName Tom Age 22 City Tulsa} is not referenced by any tuple
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar eval {
>       relvar insert OWNER {OwnerName Tom Age 22 City Tulsa}
>       relvar insert OWNERSHIP {OwnerName Tom DogName Skippy Acquired 2006}
> }
for association ::A2(::OWNERSHIP [*] ==> [1] ::DOG), in relvar ::OWNERSHIP
tuple {OwnerName Tom DogName Skippy Acquired 2006} references no tuple
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar eval {
>       relvar insert OWNER {OwnerName Tom Age 22 City Tulsa}
>       relvar insert OWNERSHIP {OwnerName Tom DogName Jumper Acquired 2006}
>       return
> }
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
|Tom      |22 |Tulsa        |
+---------+---+-------------+
::ral::relvar exists relvarName

The exists subcommand returns 1 if the relvar given by relvarName exists and 0 otherwise. The relvar name is resolved in the current namespace if it is not specified as fully qualified.

::ral::relvar identifiers relvarName

The identifiers subcommand returns a list of the identifiers of relvarName. Each element of the returned list is also a list giving the set of attributes of relvarName that constitute the identifier.

::ral::relvar insert relvarName ?name-value-list ...?

The insert subcommand inserts the tuples given by name-value-list arguments into the value of the relation stored in relvarName. The value of relvarName is modified in place. The return value is a relation value with the same heading as the value held in relvarName and whose body contains the tuples as they were actually inserted. This gives the caller access to any attributes that might have been added or modified by a relvar trace. It is an error to attempt to insert a duplicate tuple or a tuple whose heading does not match the heading of the value held in relvarName. The values of all attributes of the inserted tuples must be specified either in the command invocation or as supplied by any relvar insert traces with a valid value representation of the type associated with the attribute. However, because of relvar tracing, the tuple values given in name-value-list may not be the ones actually inserted into the relvar and relvar traces may extend the given name-value-list argument.

% relvar insert DOG {DogName Skippy Breed Dalmation}
    {DogName string Breed string} {{DogName Fido Breed Poodle} \ 
    {DogName Sam Breed Collie} {DogName Spot Breed Terrier} \ 
    {DogName Rover Breed Retriever} {DogName Fred Breed Spaniel} \ 
    {DogName Jumper Breed Mutt} {DogName Skippy Breed Dalmation}}
% relvar insert OWNER {OwnerName Tom Age 22 City Tulsa}
for association ::A1(::OWNERSHIP [+] ==> [1] ::OWNER), in relvar ::OWNER
tuple {OwnerName Tom Age 22 City Tulsa} is not referenced by any tuple
::ral::relvar intersect relvarName ?relationValue1 relationValue2 ...?

The intersect subcommand performs the relation intersection of the relation value contained in relvarName with the given relationValueN arguments and assigns the result back into relvarName. This command is shorthand for:

relvar set <relvarName> [relation intersect [relvar set <relvarName>] <relationValue1> ...]

The headings of each relationValueN must match that of the value contained in relvarName. Since the intersect operation is commutative, the order of the relationValueN arguments does not affect the result. The return value of the command is the new relation value stored in relvarName.

::ral::relvar minus relvarName relationValue

The minus subcommand performs the relation difference of the relation value contained in relvarName with the relationValue argument and assigns the result back into relvarName. This command is shorthand for:

relvar set <relvarName> [relation minus [relvar set <relvarName>] <relationValue1>]

The headings of relationValue must match that of the value contained in relvarName. Note that this operation is not commutative. The return value of the command is the new relation value stored in relvarName.

::ral::relvar names ?pattern?

The names subcommand returns a list of the currently defined relation variables. If the pattern argument is specified then only those names matching pattern are returned. Name matching is performed as for the string match command. The returned names are fully qualified.

% relvar names
::DOG ::OWNERSHIP ::OWNER
% relvar names ::D*
::DOG
::ral::relvar partition name super superAttrList sub1 sub1AttrList ?sub2 sub2AttrList sub3 sub3AttrList ...?

The partition subcommand defines a partition constraint named name. The relvar named super must have as one of its identifiers the attributes named in the superAttrList argument. The remaining arguments define the sub set relvars named subN and the attributes in those relvars that reference the super set relvar are given by the subNAttrList arguments. A partition constraint declares that every tuple in the subN relvars references exactly one tuple in the super relvar and that every tuple in the super relvar is referred to by exactly one tuple contained in one of the subN relvars. This constraint implies that the tuples in the super relvar are completely partitioned into the disjoint sub sets given by the the subN relvars.

% relvar create Lamp {SerialNo string ModelNo string Make string} SerialNo
{SerialNo string ModelNo string Make string} {}
% relvar create TableLamp {SerialNo string Shade string} SerialNo
{SerialNo string Shade string} {}
% relvar create FloorLamp {SerialNo string Height int Sockets int} SerialNo
{SerialNo string Height int Sockets int} {}
% relvar partition P1 Lamp SerialNo TableLamp SerialNo FloorLamp SerialNo
% relvar insert Lamp {SerialNo NF100 ModelNo FCN-22 Make Falcon}
for partition ::P1(::Lamp is partitioned [::TableLamp | ::FloorLamp]), in relvar ::Lamp
tuple {SerialNo NF100 ModelNo FCN-22 Make Falcon} is not referred to by any tuple
% relvar eval {
>       relvar insert Lamp {SerialNo NF100 ModelNo FCN-22  Make Falcon}
>       relvar insert TableLamp {SerialNo NF100  Shade Blue}
>       return
>     }
% relvar insert FloorLamp {SerialNo NF100 Height 72 Sockets 3}
for partition ::P1(::Lamp is partitioned [::TableLamp | ::FloorLamp]), in relvar ::Lamp
tuple {SerialNo NF100 ModelNo FCN-22 Make Falcon} is referred to by multiple tuples
% relvar insert FloorLamp {SerialNo NF101 Height 72 Sockets 3}
for partition ::P1(::Lamp is partitioned [::TableLamp | ::FloorLamp]), in relvar ::FloorLamp
tuple {SerialNo NF101 Height 72 Sockets 3} references no tuple
::ral::relvar path relvarName

The path subcommand returns the fully qualified relvar name of relvarName.

::ral::relvar procedural constraintName relvarName ?relvarName2 ...? script

The procedural subcommand defines a procedural constraint. The name of the constraint is given by the constraintName argument. At the end of any transaction (or any command that modifies a relvar if there is no ongoing transaction), script is evaluated if any of the relvarNameN relvars is modified. When script is run, it is evaluated in the namespace that is the same as the namespace implied by a fully resolved constraintName, e.g. a procedural constraint named ::myns::myproc will be evaluated in the ::myns namespace. The script must return a value that can be intepreted as a boolean. If script returns true then the constraint passes. If script returns false then the constraint is deemed to have failed and the transaction is rolled back. Procedural constraints are only evaluated at the end of a transaction and only if the relvars given in the procedural command are modified during the transaction. Compare this to the behavior of relvar trace procedures which are invoked on a tuple-by-tuple basis as the relvar value is being modified.

The following example shows a constraint that insures that the Percentage attribute always totals to 100.

% relvar create Ingredient {Name string   Percentage int} Name
{Name string Percentage int} {}
% relvar insert Ingredient {Name flour Percentage 100}
{Name string Percentage int} {{Name flour Percentage 100}}
% relvar procedural P2 Ingredient {
> set tot [relation summarizeby [relvar set Ingredient] {}\\
> ig TotalPercent int {rsum($ig, "Percentage")}]
> return [expr {[relation extract $tot TotalPercent] == 100}]
> }
% relvar eval {
> relvar insert Ingredient {Name butter Percentage 25}
> relvar updateone Ingredient ig {Name flour} {
> tuple update $ig Percentage 75}
> }
% relformat $::Ingredient Ingredient
+------+----------+
|Name  |Percentage|
|string|int       |
+------+----------+
|flour |75        |
|butter|25        |
+------+----------+
Ingredient
----------
% relvar insert Ingredient {Name salt Percentage 1}
procedural contraint, "::P2", failed
% relformat $::Ingredient Ingredient
+------+----------+
|Name  |Percentage|
|string|int       |
+------+----------+
|flour |75        |
|butter|25        |
+------+----------+
Ingredient
----------
::ral::relvar restrictone relvarName attr1 value1 ?attr2 value2 ...?

The restrictone subcommand returns a relation value containing the tuple whose attributes match those of the attrN and valueN arguments. The attrN arguments must form an identifier for the relvar. The returned relation value will be of cardinality 0 or 1. The relation value held in relvarName is not modified.

::ral::relvar set relvarName ?relationValue?

The set subcommand replaces the current value held by the relation variable named relvarName with the value given by relationValue. It is an error to attempt to assign a relation value to a relation variable that is of a different type than the type of the value that the variable currently holds. In other words, it is not possible to change the type of a relvar by assignment. The return value of the subcommand is the current value held by relvarName. If the relationValue argument is missing, then no attempt is made to change the value of relvarName. This command operates in a manner analogous to the set command for ordinary Tcl variables.

% relvar create PUPPY {PuppyName string Dame string Sire string} PuppyName
{PuppyName string Dame string Sire string} {}
% relvar set PUPPY {
>   {PuppyName string Dame string Sire string} {
>       {PuppyName Bitsy Dame Spot Sire Jumper}
>   }
>}
{PuppyName string Dame string Sire string} {{PuppyName Bitsy Dame Spot Sire Jumper}}
% relvar set PUPPY $::DOG
headings not equal, "{DogName string Breed string}"
::ral::relvar trace option type ?args?
::ral::relvar trace add variable relvarName traceops cmdPrefix
::ral::relvar trace remove variable relvarName traceops cmdPrefix
::ral::relvar trace info variable relvarName
::ral::relvar trace suspend variable relvarName script
::ral::relvar trace add eval cmdPrefix
::ral::relvar trace remove eval cmdPrefix
::ral::relvar trace info eval

The trace add variable subcommand adds a trace to relvarName. The traceops argument is a list of one or more trace operation keywords from the list:

delete
insert
set
unset
update

The trace remove variable subcommand deletes any trace on relvarName that matches traceops and command. The trace info variable subcommand returns the trace information for the relvar whose name is given by relvarName. The trace information is a list each element of which describes one trace on the relvar. Each trace information element is in turn a list consisting of two elements, the traceops and command, of the relvar trace. It is an error to request any trace operation if relvarName does not exist. The trace suspend variable subcommand suspends tracing on the relvar given by relvarName and executes script restoring tracing after script ends. This subcommand allows scripts to temporarily suspend tracing on a relvar. The trace add eval, trace remove eval and trace info eval variations perform the corresponding operation for tracing transactions via the relvar eval command. See the RELVAR TRACES section below for further details.

::ral::relvar transaction option
::ral::relvar transaction begin
::ral::relvar transaction end
::ral::relvar transaction rollback

The transaction subcommand controls the evaluation of relvar constraints. Like relvar eval, relvar transaction demarcates the boundaries of when relvar constraints are evaluated. relvar transaction begin signals the beginning of a constraint transaction. When the matching relvar transaction end is executed, all contraints for all relvars modified since the corresponding relvar transaction begin command are evaluated. Executing the relvar transaction rollback command, halts the transaction and discards all the modifications, restoring the relvar state to that which existed before the execution of relvar transaction begin. This command is complementary to relvar eval in that it provides the same behavior but for those circumstances where accumulating the relvar modifications into a single script is not convenient or possible. The command returns the empty string. If relvar modifications are such that the constraints are violated, then relvar transaction end will throw an error.

::ral::relvar uinsert relvarName ?name-value-list ...?

The uinsert subcommand inserts the tuples given by name-value-list arguments into the value of the relation stored in relvarName. The value of relvarName is modified in place. The return value is a relation value with the same heading as the value held in relvarName and whose body contains the tuples as they were actually inserted. This gives the caller access to any attributes that might have been added or modified by a relvar trace. The uinsert command has union-like semantics and so any attempt to insert a duplicate tuple is silently ignored. It is an error to attempt to insert a tuple whose heading does not match the heading of the value held in relvarName. The values of all attributes of the inserted tuples must be specified either in the command invocation or as supplied by any relvar insert traces with a valid value representation of the type associated with the attribute. However, because of relvar tracing, the tuple values given in name-value-list may not be the ones actually inserted into the relvar and relvar traces may extend the given name-value-list argument.

::ral::relvar union relvarName ?relationValue1 relationValue2 ...?

The union subcommand performs the relation union of the relation value contained in relvarName with the given relationValueN arguments and assigns the result back into relvarName. This command is shorthand for:

relvar set <relvarName> [relation union [relvar set <relvarName>] <relationValue1> ...]

The headings of each relationValueN must match that of the value contained in relvarName. Since the union operation is commutative, the order of the relationValueN arguments does not affect the result. The return value of the command is the new relation value stored in relvarName.

::ral::relvar unset ?relvarName ...?

The unset subcommand deletes all the relation variables whose names are given as the subcommand arguments. The corresponding Tcl variables that were created when the relvar was created are also unset. This command operates in a manner analogous to the unset command for ordinary Tcl variables. It is an error to attempt to unset a relvar that is associated with any constraints.

::ral::relvar update relvarName tupleVarName expression script

The update subcommand modifies the values of tuples in the relation value contained in the relation variable given by relvarName. Each tuple in relvarName is successively assigned to the tuple variable given by tupleVarName and expression is evaluated. If the result of the evaluation is true, then script is evaluated. The return value of script is then used to update the corresponding tuple in relvarName. The return value of the relvar update subcommand is a relation value with the same heading as the value held in relvarName and whose body contains the tuples as they were actually updated into the relvar. This gives the caller access to any attributes that might have been modified by a relvar trace. If the script throws an error or the modified value of a tuple cannot be updated into relvarName, all changes to relvarName are discarded and the value of relvarName is restored to its previous value. Should script execute a break or otherwise arrange to return a break result code, then the tuple is updated, but no further tuples in the relvar are considered.

% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar update OWNER o {[tuple extract $o OwnerName] eq "Sue"} {
>       tuple update $o Age [expr {[tuple extract $o Age] + 1}]
>     }
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |25 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar update OWNER o {[tuple extract $o OwnerName] eq "George"} {
>       tuple update $o OwnerName Alfonse
>     }
for association ::A1(::OWNERSHIP [+] ==> [1] ::OWNER), in relvar ::OWNER
tuple {OwnerName Alfonse Age 35 City Sunnyvale} is not referenced by any tuple
for association ::A1(::OWNERSHIP [+] ==> [1] ::OWNER), in relvar ::OWNERSHIP
tuple {OwnerName George DogName Fido Acquired 2001} references no tuple
tuple {OwnerName George DogName Sam Acquired 2000} references no tuple
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |25 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
::ral::relvar updateone relvarName tupleVarName id-name-value-list script

The updateone subcommand modifies at most one tuple from the relation variable given by the relvarName argument. The id-name-value-list must be list containing an even number of elements which are attribute names alternating with attribute values. The set of attribute names in id-name-value-list must form one of the identifiers of relvarName. If relvarName contains a tuple whose attribute values match those in name-value-list then that tuple is assigned to tupleVarName and script is executed. The tuple value returned by script replaces the original tuple, modifying relvarName in place. If no matching tuple is found, then relvarName is unchanged. This subcommand is useful in those contexts where the attribute values of an identifier are known and evaluating an expression over all the tuples in relvarName is superfluous. The return value is a relation value with the same heading as the value held in relvarName and whose body contains either the single tuple that was updated or is empty if no matching tuple was found. This gives the caller access to any attributes that might have been modified by a relvar trace.

% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |35 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
% relvar updateone OWNER o {OwnerName George} {
> tuple update $o Age 37 City {New York}
> }
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |24 |Cupertino    |
|George   |37 |New York     |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |42 |San Francisco|
+---------+---+-------------+
::ral::relvar updateper relvarName relationValue

The updateper subcommand modifies the relation value held in relvarName according to the tuples found in relationValue. The heading of relationValue must be a subset (possibly improper) of the heading of the value held in relvarName. The heading of relationValue must also contain all of the attributes of at least one of the identifiers of relvarName. The action of updateper is to update the non-identifying attributes of all the tuples in relvarName whose identifying attributes are equal to the corresponding attributes in relationValue. The return value of the command is a relation value with the same heading as the value held in relvarName and whose body contains tuples that were updated. This gives the caller access to any attributes that might have been modified by a relvar trace. This command is most useful when a subset of tuples from a relvar are modified by a series of relational expressions and the results of those modification need to be updated back into the original relvar.

% relvar updateper OWNER [relation table {OwnerName string Age int} {
        George 37} {
        Jim 44}]
% puts [relformat $::OWNER]
+---------+---+-------------+
|OwnerName|Age|City         |
|string   |int|string       |
+---------+---+-------------+
|Sue      |25 |Cupertino    |
|George   |37 |Sunnyvale    |
|Alice    |30 |San Jose     |
|Mike     |50 |San Jose     |
|Jim      |44 |San Francisco|
+---------+---+-------------+

RELVAR TRACES

By analogy to tracing ordinary variables in Tcl, relvars can also be traced. However, relvar tracing must account for the operations that are applied to relvars. There are five operations that may be traced on the relation values held in relvars and one operation that allows tracing of transactions on relvars. For these operations, if a command prefix has been registered using relvar trace add variable or relvar trace add transaction then that command prefix will have additional arguments appended and will be invoked as described below. Relvar traces operate in a very similar fashion as traces on ordinary Tcl variables. The trace command is invoked when the corresponding relvar operation is invoked and is invoked in the context of the caller of the relvar operation, which, in general, is different from the caller of the relvar trace add command. When executing a variable type trace for a relvar, all other variable type tracing for that relvar is inhibited. If multiple traces have been added to a relvar, the traces are invoked in the order of most recent first to oldest last.

delete

A delete trace is invoked for each tuple in a relvar that is deleted. Tuples are deleted from relvars by invocations of relvar delete or relvar deleteone. The delete trace command is invoked as:

cmdPrefix delete relvarName tupleValue

where cmdPrefix is the command prefix of the trace as given in relvar trace add variable, the string delete indicates that a tuple is to be deleted from the relvar, relvarName is the fully qualified name of the relvar and tupleValue is the value of the tuple about to be deleted. The trace command is invoked before the tuple is actually removed from the relation value held in the relvar. If cmdPrefix throws an error, then no other delete traces in the chain of delete traces for the relvar are invoked and tupleValue is not removed from the relvar value.

insert

An insert trace is invoked for each tuple in a relvar that is inserted. Tuples are inserted into relvars by invocations of relvar insert. The insert trace command is invoked as:

cmdPrefix insert relvarName tupleValue

where cmdPrefix is the command prefix of the trace as given in relvar trace add variable, the string insert indicates that a tuple is to be inserted into the relvar, relvarName is the fully qualified name of the relvar and tupleValue is the value of the tuple about to be inserted The trace command is invoked before the tuple is actually inserted into the relation value held in the relvar. The cmdPrefix command must return a Tuple value. The returned Tuple value is passed along to the next insert trace command. The returned Tuple from the last trace command in the chain is then inserted into the relvar. Insert trace commands may choose to modify the value of tupleValue but are required to return a value that can be coerced into a Tuple type and the heading of the returned Tuple of the last trace command in the chain must match that of the relvar if it is to be successfully inserted. If cmdPrefix throws an error, then no other insert traces in the chain of insert traces for the relvar are invoked and tupleValue is not inserted into the relvar value.

set

A set trace is invoked each time that the relation value held in a relvar is assigned. Relations values are assigned to relvars by invocation of the relvar set, relvar union, relvar intersect or relvar minus command. The set trace command is invoked as:

cmdPrefix set relvarName relationValue

where cmdPrefix is the command prefix of the trace as given in relvar trace add variable, the string set indicates that a relation value is to be assigned to the relvar, relvarName is the fully qualified name of the relvar and relationValue is the relation value that is about to be assigned to the relvar. The trace command is invoked before the relation is actually assigned to the relvar. The cmdPrefix command must return a Relation value. The returned Relation value is passed along to the next set trace command. The returned Relation from the last trace command in the chain is then assigned to the relvar. Set trace commands may choose to modify the value of relationValue but are required to return a value that can be coerced into a Relation type and the heading of the returned Relation of the last trace command in the chain must match that of the relvar if it is to be successfully assigned If cmdPrefix throws an error, then no other set traces in the chain of set traces for the relvar are invoked and relationValue is not assigned to the relvar.

unset

An unset trace is invoked each time a relvar is destroyed. Relvars are destroyed by the invocation of the relvar unset command. Note that due to a limitation of Tcl, relvar unset traces are not invoked when an interpreter is deleted. The unset trace command is invoked as:

cmdPrefix unset relvarName

where cmdPrefix is the command prefix of the trace as given in relvar trace add variable, the string unset indicates that the relvar is being destroyed, and relvarName is the fully qualified name of the relvar. The trace command is invoked before the relvar is actually destroyed so the relation value stored in the relvar is still intact. Any errors thown by cmdPrefix are ignored.

update

An update trace is invoked for each tuple in a relvar that is updated. Tuples are updated into relvars by invocations of relvar update, relvar updateone or relvar updateper commands. The update trace command is invoked as:

cmdPrefix update relvarName oldTupleValue newTupleValue

where cmdPrefix is the command prefix of the trace as given in relvar trace add variable, the string update indicates that a tuple is to be updated in the relvar, relvarName is the fully qualified name of the relvar, oldTupleValue is the current value of the tuple in the relvar and newTupleValue is the value that the tuple will have when the update is performed. The trace command is invoked before the tuple is actually updated in the relation value held in the relvar. The cmdPrefix command must return a Tuple value. The returned Tuple value is passed along to the next update trace command. The returned Tuple from the last trace command in the chain is then updated into the relvar. Update trace commands may choose to modify the value of newTupleValue but are required to return a value that can be coerced into a Tuple type and the heading of the returned Tuple of the last trace command in the chain must match that of the relvar if it is to be successfully updated. If cmdPrefix throws an error, then no other update traces in the chain of update traces for the relvar are invoked and tupleValue is not updated into the relvar value.

transaction

A transaction trace is invoked each time that a relvar eval begins and ends or when relvar transaction commands are invoked. Eval traces are different from other relvar traces in that they provide a means of determining the boundaries of a transaction rather than specific operations on a relvar. The transaction trace command is invoked as:

cmdPrefix transaction op level

where cmdPrefix is the command prefix of the trace as given in relvar trace add transaction, the string transaction indicates that the relvar transaction is in progress, the op is either the string "begin" or "end" indicating whether or not the relvar transaction is just starting or is ending and level is an integer greater than zero indicating the nesting depth of the transaction. The transaction trace is invoked with the "begin" op before the script associated with a relvar eval or relvar transaction is executed and is invoked with the "end" op after the script is executed but before the relvar constraints are evaluated for the transaction. Any errors thown by cmdPrefix are ignored.

See Also

relation, tuple

Keywords

relation, variable