File: DBDefs.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Contents: Definitions of DBStorage and DBView types.
File created by Rick Cattell, 7-Jun-81
Last edited by:
Cattell on: August 2, 1983 1:44 pm
MBrown on: 9-Jun-81 15:33:33
Eric Bier on: 17-Aug-81 14:20:59
Willie-Sue on February 15, 1985 11:22:21 am PST
Donahue, April 10, 1986 12:16:09 pm PST
Widom, September 9, 1985 5:06:14 pm PDT
DIRECTORY
BasicTime USING[GMT, nullGMT],
CardTable USING[Ref],
DBCommon,
DBStorage,
SymTab USING[Ref],
Rope;
DBDefs: CEDAR DEFINITIONS = BEGIN
ROPE: TYPE = Rope.ROPE;
Datum: TYPE = {boolean, integer, rope, time};
The builtin types of Cypress
Type: TYPE = {null, boolean, integer, rope, time, entity};
TypeCode: TYPE = RECORD[code: DBCommon.TID ← 0];
These are used to give the types of fields in tuples
Here are the builtin type codes. Note: the type codes for builtin types are limited to be anything less than DBStorage.MaxSystemTupleID. These TID's are used for system tuple set ID's, so they can also be used unambiguously to identify the types of builtin objects (ie., it cannot be the case that any domain created in a program can have a TID in the range 0 <= x < DBStorage.MaxSystemTupleID).
boolType: TypeCode = TypeCode[code: ORD[Type[boolean]]];
intType: TypeCode = TypeCode[code: ORD[Type[integer]]];
ropeType: TypeCode = TypeCode[code: ORD[Type[rope]]];
timeType: TypeCode = TypeCode[code: ORD[Type[time]]];
anyDomainType: TypeCode = TypeCode[code: ORD[Type[null]]];
anyDomainType simply needs to be something that is outside the range of the primitive types but not a legal domain TID
IsPrimitive: PROC[type: TypeCode] RETURNS[yes: BOOL] =
INLINE { yes ← type.code IN [ ORD[Type[boolean]] .. ORD[Type[time]] ] };
Value: TYPE = RECORD [SELECT type: Type FROM
boolean => [value: BOOL],
integer => [value: INT],
entity => [value: Entity],
rope => [value: ROPE],
time => [value: BasicTime.GMT],
null => [],
ENDCASE];
NullValue: Value = Value[null[]];
ValueSequence: TYPE = REF ValueSequenceObject;
ValueSequenceObject: TYPE = RECORD[SEQUENCE count: CARDINAL OF Value];
Value sequences are used as arguments to the operations to create or lookup relationships in the database
Index: TYPE = REF IndexObject;
IndexObject: TYPE = RECORD[ fields: FieldSequence, key: CARDINAL ← 0, isKey: BOOLFALSE, index: DBCommon.TupleHandle ← NIL ];
An index over a relation is specified by giving the ordered sequence of the attributes to be used in computing the index entries; remaining fields of the object are filled in by the Model level and should be treated as readonly. If the index field is NIL, then this is an index for a surrogate relation (the isKey field will be true and the field sequence will be of length 1 and refer to the first field only)
FieldSequence: TYPE = REF FieldSequenceObject;
FieldSequenceObject: TYPE = RECORD[SEQUENCE count: CARDINAL OF CARDINAL];
The client programs are given back handles to the entries in the schema cache maintained by the Storage Level. Each of the entries includes a "key" that is changed whenever the storage level cache is flushed — which only happens when the cache state is inconsistent with the state of the database. Before using one of the handles for domain or relation objects, it is necessary to check that the key stored in the object is equal to the key stored in the schema cache for the segment.
Domain: TYPE = REF DomainObject;
Relation: TYPE = REF RelationObject;
Attribute: TYPE = REF AttributeHandle;
AttributeHandle: TYPE = RECORD[pos: CARDINAL, relation: Relation];
Attribute handles simply record the relative position of the attribute in a relation.
Entity: TYPE = REF EntityObject;
EntityObject: TYPE = RECORD[domain: Domain, name: Rope.ROPE, tuple: DBCommon.TupleHandle];
An entity is a typed tuple in the database. (Note that the tuple contains no type information of its own -- the domain stored in the object is that used when the entity was created.)
NullEntity: Entity = NIL;
The empty entity
TupleSet: TYPE = DBCommon.TupleHandle;
Relship: TYPE = REF RelshipObject;
RelshipObject: TYPE = RECORD[ relation: Relation, handle: DBCommon.TupleHandle ];
A relship gives the database tuple and the relation to which it belongs. The relation contains all of the information necessary to interpret the tuple. Note that it may be possible that the handle is in fact an entity -- this is true if the surrogate relationship optimization is used. If this is the case, the relation may not necessarily allow access to all of the fields of the tuple (since some of them may be part of other relations!!)
The model level caches the schema information for each currently declared segment (at least as much as is necessary to handle all operations that can be performed using the declarations that have been performed by client programs). The transaction handles that are passed around contain all of this schema information. When a transaction is committed or aborted that has made a schema update, the model level must update its cached information
The definitions below give the structure of the schema table stored for each segment
SegmentHandle: TYPE = REF SegmentObject;
SegmentObject: TYPE = RECORD [
segment: Segment,
the name of the segment
server: Rope.ROPE,
The name of the server on which the segment resides. This is used to create transactions to access the segment
key: CARDINAL ← 0,
This key is stored with each domain or relation object that is in the domainTable or relationTable. When the objects are used, the key stored in the object must agree with the key stored in the segment handle for the object. This key changes each time the domain and relation caches are flushed, which is whenever the version stamps stored in this table and in the database differ. The keys are managed in this way so that pointers to information in the domain or relation tables can be handed out to the DB level while maintaining consistency with the segment level caches (which are always transaction-consistent with the database contents).
cacheTrashed: BOOLTRUE,
If TRUE, then the schema cache was trashed by an aborted transaction that attempted a schema update. The next OpenTransaction after an abort that updates the schema will return schemaInvalid = TRUE
indices: ARRAY[0..DBCommon.systemIndexCount) OF DBCommon.TupleHandle,
The indices on the DomainDomain and RelationDomain for the segment (where to get started if something has to be done from scratch!)
domainTable, relationTable: SymTab.Ref,
The domains and relations in the schema are stored in a symbol table accessed by domain or relation name.
Note: These tables may contain more entries than have currently been declared by the client program. For example, when a domain is declared, all of its supertypes will be entered in the table (so that type-checking can always be done without database accesses!). Also, when a relation is declared, all of its attributes and indices will be entered in the table, so that new relations can be added to the database while maintaining all of the necessary indices and not have to further interrogate the schema.
The basic plan is that the only actual database reads and writes performed during a Cypress operation will be on the data -- all of the schema information will be in the table (or the table will be invalid, in which case the operation will fail).
domainsByTID: CardTable.Ref,
This table hashes the tuple ids of domains, so that DomainFromTuple is efficient in the case that the domain already has been cached
attributeTable: CardTable.Ref,
The attribute table is index by the tuple id of the attribute tuple; the entries in the table are relations (the relation for the attribute). This avoids reading the information from the database when entities are being deleted
schemaVersionStamp: INT ← 0,
the version stamp for the schema
schemaUpdated: BOOLFALSE
if the schema is updated, the information stored in the table will refer to the new version, rather than the one stored in the database
];
DomainObject: TYPE = RECORD [
name: ROPE,
name of this domain
segment: Segment,
The segment in which the domain lives
key: CARDINAL,
The key that was stored in the segment handle for the segment when this object was created. Before using the information stored here it is necessary to validate that this key is equal to the key that is now stored in the segment handle.
tupleSet: DBCommon.TupleHandle,
The tuple set corresponding to the domain. The TID of the tupleset is also used as the type code for the domain
detailsKnown: BOOLFALSE,
If the details are not known, then the tuple for the domain has not yet been read. If this is so, then the index and entityNameHandles are not valid
index: DBCommon.TupleHandle,
The index for this domain (used when declaring or fetching entities from the domain)
entityNameHandle: DBStorage.FieldHandle ← NIL,
The field handle used to access names of entities
superTypeKnown: BOOLFALSE,
If TRUE, then the supertype of the domain is stored in the superType field. Note that the superType may be NIL when superTypeKnown = TRUE if the domain has no supertype.
superType: Domain,
If non-NIL, the current supertype of the domain
surrogatesKnown: BOOLFALSE,
If TRUE, then the relation list gives a complete description of all of the surrogates of the relation.
surrogates: RelationList
A list of all of the surrogates for the domain (this is needed when destroying entities)
];
RelationList: TYPE = REF RelationListObject;
RelationListObject: TYPE = RECORD[relation: Relation, next: RelationList ← NIL];
RelationObject: TYPE = RECORD [
name: ROPE,
name of this relation
segment: Segment,
The segment in which this relation lives
key: CARDINAL,
The key that was stored in the segment handle for the segment when this object was created. Before using the information stored here it is necessary to validate that this key is equal to the key that is now stored in the segment handle.
tupleSet: DBCommon.TupleHandle,
corresponding system tupleset.
attributesKnown: BOOLFALSE,
If this is true, then the surrogate, attribute and index information is consistent with the database. When a relation object is created through DeclareRelation, then this information will be filled in; if it is created through a Relation enumeration, it may not always be up-to-date
isProperty: BOOLFALSE,
If this is true, then the relation was defined using DeclareProperty; this allows the SetP and GetP operations to be used
isSurrogate: BOOLFALSE,
TRUE iff isProperty and this relation is a surrogate (ie., the attributes of the relation are stored with the entities in the domain of its first attribute)
surrogateDomain: Domain ← NIL,
If the relation is a surrogate, this gives the Domain in which the relationships are actually stored
surrogateGroupHandle: DBStorage.FieldHandle ← NIL,
If the relation is a surrogate, this gives the field handle for opening a group scan on the relation
attributes: AttrSeqHandle,
a sequence containing the properties of the attributes for the relation
indicesKnown: BOOLFALSE,
If this is true, then the surrogate, attribute and index information is consistent with the database. When a relation object is created through DeclareRelation, then this information will be filled in; if it is created through a Relation enumeration, it may not always be up-to-date
keys: LIST OF IndexHandle,
a list of all of the keys for the relation
indices: LIST OF IndexHandle
A list of additional client-specified indices on this relation; when a tuple is created or destroyed, all indices must be updated
];
AttrSeqHandle: TYPE = REF AttributeSequence;
AttributeSequence: TYPE = RECORD[ SEQUENCE count: CARDINAL OF REF AttributeObject ];
The elements of index sequences are intended to be indices into the schemaTable of the segment object in which they are stored
AttributeObject: TYPE = RECORD [
name: ROPE,
name of this attribute
type: TypeCode,
data type of this attribute
tuple: DBCommon.TID,
The tuple ID of the attribute (which is the index into the attribute table)
domain: Domain,
If the type is some domain type, then this points back to the domain object
fh: DBStorage.FieldHandle ← NIL,
field handle for this attribute
indices: LIST OF IndexHandle
a list of all of the indices that are affected if this attribute changes
];
IndexHandle: TYPE = REF IndexHandleObject;
IndexHandleObject: TYPE = RECORD[indexHandle: DBCommon.TupleHandle, isKey: BOOL, index: FieldSequence];
An index records the tuple id of the index root and the list of factors that make up the index entries
RelshipSet: TYPE = REF RelshipSetObject;
RopeSequence: TYPE = REF RopeSequenceObject;
RopeSequenceObject: TYPE = RECORD[SEQUENCE length: CARDINAL OF Rope.ROPE];
RelshipSetObject: TYPE = RECORD[ relation: Relation,
variant: SELECT type: * FROM
onlyOne => [tuple: DBCommon.TupleHandle],
simpleScan => [scanHandle: DBStorage.IndexScanHandle],
tupleSet => [scanHandle: DBStorage.TuplesetScanHandle],
group => [scanHandle: DBStorage.GroupScanHandle],
complexScan => [handle: REF ComplexScanObject],
scanForEntity => [handle: REF EntityScanObject]
ENDCASE ];
ComplexScanObject: TYPE = RECORD[low, high, thisOne: RopeSequence, scanHandle: DBStorage.IndexScanHandle];
EntityScanObject: TYPE = RECORD[entityTuple: DBCommon.TupleHandle, fields: LIST OF DBCommon.TupleHandle, relationsAlreadyDone: LIST OF DBCommon.TupleHandle, thisRelation: Relation, scanHandle: DBStorage.GroupScanHandle];
EntitySet: TYPE = REF EntitySetObject;
EntitySetObject: TYPE = RECORD[domain: Domain, scanHandle: DBStorage.IndexScanHandle];
DomainSet: TYPE = REF DomainSetObject;
RelationSet: TYPE = REF RelationSetObject;
DomainSetObject: TYPE = RECORD[segment: Segment,
variant: SELECT type:* FROM
index => [scanHandle: DBStorage.IndexScanHandle],
group => [scanHandle: DBStorage.GroupScanHandle]
ENDCASE ];
RelationSetObject: TYPE = RECORD[segment: Segment,
variant: SELECT type: * FROM
index => [scanHandle: DBStorage.IndexScanHandle],
relationsForDomain =>
[scanHandle: DBStorage.GroupScanHandle, lastTuple: DBCommon.TupleHandle]
ENDCASE ];
Constraint: TYPE = REF ConstraintObject;
ConstraintObject: TYPE = RECORD[SEQUENCE count: CARDINAL OF ValueConstraint];
ValueConstraint: TYPE = RECORD[SELECT type: Type FROM
boolean => [value: BOOL],
integer => [low: INTFIRST[INT], high: INTLAST[INT]],
entity => [value: Entity],
rope => [low: ROPENIL, high: ROPENIL],
time => [low: BasicTime.GMT ← BasicTime.nullGMT , high: BasicTime.GMT ← BasicTime.nullGMT],
null => [],
ENDCASE ];
Types the client may need that are defined in DBCommon:
Segment: TYPE = DBCommon.Segment;
SegmentIndex: TYPE = DBCommon.SegmentIndex;
FirstLast: TYPE = DBCommon.FirstLast;
END.