File DBModelSystemImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Contents: Initialization of and operations on system tuples
Last modified by:
Eric Bier on: 18-Aug-81 14:48:57
Rick Cattell on: September 14, 1983 4:19 pm
Willie-Sue on February 15, 1985 5:21:28 pm PST
Donahue, September 5, 1985 5:44:56 pm PDT
Widom, September 9, 1985 5:06:58 pm PDT
DIRECTORY
Basics USING [LowHalf],
DBCommon,
DBStorage,
DBDefs,
DB,
DBModelPrivate,
Rope USING [ROPE, Concat];
DBModelSystemImpl: CEDAR PROGRAM
IMPORTS DB, DBStorage, DBModelPrivate, Basics, Rope
EXPORTS DBDefs, DBModelPrivate =
BEGIN OPEN DBStorage, DBCommon, DBDefs, DBModelPrivate;
ROPE: TYPE = Rope.ROPE;
MaxVTID: CARDINAL = DBStorage.MaxSystemTupleID;
Property: TYPE = Attribute;
Value Types
AnyDomainType,
BoolType,
IntType,
TimeType,
RopeType: PUBLIC DataType;
RecordType: PUBLIC DataType;
Definitions of system tuple (virtual) tids
DomainTSID: LONG CARDINAL = 1;
RelationTSID: LONG CARDINAL = 2;
AttributeTSID: LONG CARDINAL = 3;
DataTypeTSID: LONG CARDINAL = 4;
IndexTSID: LONG CARDINAL = 5;
IndexFactorTSID: LONG CARDINAL = 6;
aRelationTSID: LONG CARDINAL = 7;
aTypeTSID: LONG CARDINAL = 8;
aUniquenessTSID: LONG CARDINAL = 9;
aLengthTSID: LONG CARDINAL = 10;
aLinkTSID: LONG CARDINAL = 11;
aDomainTSID: LONG CARDINAL = 12;
aUnlinkedTSID: LONG CARDINAL = 13;
ifIndexTSID: LONG CARDINAL = 14;
ifOrdinalPositionTSID: LONG CARDINAL = 15;
ifAttributeTSID: LONG CARDINAL = 16;
dSubTypeTSID: LONG CARDINAL = 17;
DummyID: LONG CARDINAL = 19; -- used for one fake relation
RopeTypeID: LONG CARDINAL = 20;
IntTypeID: LONG CARDINAL = 21;
TimeTypeID: LONG CARDINAL = 22;
BoolTypeID: LONG CARDINAL = 23;
RecordTypeID: LONG CARDINAL = 24;
AnyDomainTypeID: LONG CARDINAL = 25;
The System tuple abstraction
STSVecType: TYPE = ARRAY[1..MaxVTID] OF TupleHandle;
passed to storage level so that proper tuple can be returned when a GetF is done and the tid is < SL.MaxSystemTupleID.
systemTupleVec: PUBLIC REF STSVecType ← NEW[STSVecType← ALL[NIL]];
attributeIDCount: LONG CARDINAL← 0;
used in DefineSystemRelation and DefineSystemAttribute.
The system-defined domains, relations, and attributes: grouped by domains
Items declared to be Properties are attributes with no relation; we don't need the relation
because it is an internal private binary surrogate relation. The [binary] relations that the
client may access require both attributes and the relation entity itself, so that the client
may perform RelationSubset and do a GetP in both directions.
DomainDomain: PUBLIC Domain; -- one element per client-defined domain
dHandleProp: PUBLIC Property; -- the storage level tupleset handle
dIndexProp: PUBLIC Property; -- the storage level index handle for this domain
dSubType: PUBLIC Relation; -- one element per direct sub-super type relationship
dSubTypeOf: PUBLIC Attribute; -- domain: the super-type
dSubTypeIs: PUBLIC Attribute; -- domain: the sub-type
RelationDomain: PUBLIC Domain; -- one element per client-defined relation
rHandleProp: PUBLIC Property; -- the storage level tupleset handle
r1to1Prop: PUBLIC Property; -- TRUE iff this relation is a surrogate relation
AttributeDomain: PUBLIC Domain; -- one element per client-defined attribute
aHandleProp: PUBLIC Property; -- the storage level handle for this field
aTypeCodeProp: PUBLIC Property; -- tid of the type entity, or zero if domain-valued
aTypeEntityProp: PUBLIC Property; -- the domain this attribute refs, or NIL if datum-valued
aRelation: PUBLIC Relation; -- one element per client-defined attribute
aRelationOf: PUBLIC Attribute; -- the attribute
aRelationIs: PUBLIC Attribute; -- relation of the attribute
aType: PUBLIC Relation; -- one element per client-defined attribute
aTypeOf: PUBLIC Attribute; -- the attribute
aTypeIs: PUBLIC Attribute; -- domain or datatype of the attribute
aUniqueness: PUBLIC Relation; -- one element per client-defined attribute
aUniquenessOf: PUBLIC Attribute; -- the attribute
aUniquenessIs: PUBLIC Attribute; -- INT corresponding to its uniqueness
aLength: PUBLIC Relation; -- one element per client-defined attribute
aLengthOf: PUBLIC Attribute; -- the attribute
aLengthIs: PUBLIC Attribute; -- INT corresponding to attribute's length
aLink: PUBLIC Relation; -- one element per client-defined attribute
aLinkOf: PUBLIC Attribute; -- the attribute
aLinkIs: PUBLIC Attribute; -- INT corresponding to its LinkType.
aDomain: PUBLIC Relation; -- exported to DBModelPrivate: one elt per client-defined attribute
aDomainOf: PUBLIC Attribute; -- the attribute
aDomainIs: PUBLIC Attribute; -- non-NIL only if this is the first (targetted) attribute of
a surrogate relation, equals domain where actually
stored (i.e., equals aTypeEntityProp when non-NIL)
aUnlinked: PUBLIC Relation; -- exported to DBModelPrivate: one elt per client-defined attribute
aUnlinkedOf: PUBLIC Attribute; -- the attribute
aUnlinkedIs: PUBLIC Attribute; -- non-NIL only if this attribute is NOT linked, in which
case it equals aTypeProp (i.e., the domain referenced)
DataTypeDomain: PUBLIC Domain; -- RopeTypeEntity, BoolTypeEntity, etc. are of this domain
The DataType entities
RopeTypeEntity, IntTypeEntity, TimeTypeEntity, BoolTypeEntity, RecordTypeEntity, AnyDomainTypeEntity: PUBLIC Entity;
IndexDomain: PUBLIC Domain; -- one element per client-defined index
iHandleProp: PUBLIC Property; -- index handle, set by storage level
IndexFactorDomain: PUBLIC Domain; -- one element per attribute in an index
ifIndex: PUBLIC Relation; -- one element per attribute in an index (an "index factor")
ifIndexOf: PUBLIC Attribute; -- the index factor
ifIndexIs: PUBLIC Attribute; -- the index this index factor belongs to
ifOrdinalPosition: PUBLIC Relation; -- one element per index factor
ifOrdinalPositionOf: PUBLIC Attribute; -- the index factor
ifOrdinalPositionIs: PUBLIC Attribute; -- the position of this index factor in the ordering
ifAttribute: PUBLIC Relation; -- one element per index factor
ifAttributeOf: PUBLIC Attribute; -- the index factor
ifAttributeIs: PUBLIC Attribute; -- the attribute this index factor indexes
Other global variables, exported to DBModelPrivate:
defaultNameHandle, attributeNameHandle, tupleSetNameHandle: PUBLIC DBStorage.FieldHandle;
defaultNameAttribute: PUBLIC Attribute;
DefaultNameSize: CARDINAL = 20;
The following shouldn't go into DB because they might get used before initialized
minfString: ROPE ← ""; -- less than any other string
infString: ROPE ← "\177"; -- greater than any other string
InitializeSystemTuples: PUBLIC PROC = TRUSTED
BEGIN dNameProp, rNameProp, aNameProp: Property; -- only need temporarily
DBStorage.SetSystemTupleTable[systemTupleVec];
Define the system domains
DomainDomain← DefineSystemDomain[DomainTSID, "Domain"];
RelationDomain← DefineSystemDomain[RelationTSID, "Relation"];
AttributeDomain← DefineSystemDomain[AttributeTSID, "Attribute"];
DataTypeDomain← DefineSystemDomain[DataTypeTSID, "DataType"];
IndexDomain← DefineSystemDomain[IndexTSID, "Index"];
IndexFactorDomain← DefineSystemDomain[IndexFactorTSID, "IndexFactor"];
Define the DataType atoms
RopeType← $ROPE;
IntType← $INT;
TimeType← $GMT;
BoolType← $BOOL;
AnyDomainType← $ANY;
RecordType← $RECORD;
Define the DataType entities
RopeTypeEntity ← DefineSystemEntity[RopeTypeID, DataTypeDomain, "ROPE"];
IntTypeEntity ← DefineSystemEntity[IntTypeID, DataTypeDomain, "INT"];
TimeTypeEntity ← DefineSystemEntity[TimeTypeID, DataTypeDomain, "GMT"];
BoolTypeEntity ← DefineSystemEntity[BoolTypeID, DataTypeDomain, "BOOL"];
RecordTypeEntity ← DefineSystemEntity[RecordTypeID, DataTypeDomain, "RECORD"];
AnyDomainTypeEntity ← DefineSystemEntity[AnyDomainTypeID, DataTypeDomain, "ANY"];
FakeTheNameHandle[]; -- must call after RopeType defined but before any real entities
Define (private) properties of domain, relation, attribute, and index entities
dHandleProp← DefinePrivateProperty[
DomainDomain, "dHandleProp", RecordType, DBStorage.TuplesetObjectSize];
dHandle must be first field for proper storage level operation!
dNameProp← DefinePrivateProperty[DomainDomain, "dName", RopeType, DefaultNameSize];
tupleSetNameHandle← dNameProp.fh;
dIndexProp← DefinePrivateProperty[DomainDomain, "dIndexProp", $IndexDomain];
rHandleProp← DefinePrivateProperty[
RelationDomain, "rHandleProp", RecordType, DBStorage.TuplesetObjectSize];
rHandle must be first field for proper DBStorage operation!
rNameProp← DefinePrivateProperty[
RelationDomain, "rNameProp", RopeType, DefaultNameSize];
don't need handle because assume identical pos&size as tupleChangeNameHandle above
r1to1Prop← DefinePrivateProperty[RelationDomain, "r1to1", BoolType];
aHandleProp← DefinePrivateProperty[
AttributeDomain, "aHandleProp", RecordType, DBStorage.FieldObjectSize];
handle need not be first field, but make it that way anyway like other system tuples
aNameProp← DefinePrivateProperty[AttributeDomain, "aName", RopeType];
attributeNameHandle← aNameProp.fh;
aTypeCodeProp← DefinePrivateProperty[
AttributeDomain, "aTypeCodeProp", IntType];
aTypeEntityProp← DefinePrivateProperty[
AttributeDomain, "aTypeEntityProp", $DataTypeDomain];
iHandleProp← DefinePrivateProperty[
IndexDomain, "iHandleProp", RecordType, DBStorage.IndexObjectSize];
iHandle must be first field of Index entity for proper DBStorage operation!
Define the system relations and their attributes
FakeTheTypeAndLinkRelations[];
[aRelation, aRelationOf, aRelationIs]← DefineSystemBinary[
id: aRelationTSID, name: "aRelation", of: $AttributeDomain, is: $RelationDomain];
[aUniqueness, aUniquenessOf, aUniquenessIs]← DefineSystemBinary[
id: aUniquenessTSID, name: "aUniqueness", of: $AttributeDomain, is: IntType];
[aLength, aLengthOf, aLengthIs]← DefineSystemBinary[
id: aLengthTSID, name: "aLength", of: $AttributeDomain, is: IntType];
[aDomain, aDomainOf, aDomainIs]← DefineSystemBinary[
id: aDomainTSID, name: "aDomain", of: $AttributeDomain, is: $DomainDomain];
[aUnlinked, aUnlinkedOf, aUnlinkedIs]← DefineSystemBinary[
id: aUnlinkedTSID, name: "aUnlinked", of: $AttributeDomain, is: $DomainDomain];
[ifIndex, ifIndexOf, ifIndexIs]← DefineSystemBinary[
id: ifIndexTSID, name: "ifIndex", of: $IndexFactorDomain, is: $IndexDomain];
[ifOrdinalPosition, ifOrdinalPositionOf, ifOrdinalPositionIs]← DefineSystemBinary[
id: ifOrdinalPositionTSID, name: "ifOrdinalPosition", of: $IndexFactorDomain, is: IntType];
[ifAttribute, ifAttributeOf, ifAttributeIs]← DefineSystemBinary[
id: ifAttributeTSID, name: "ifAttribute", of: $IndexFactorDomain, is: $AttributeDomain];
[dSubType, dSubTypeOf, dSubTypeIs]← DefineSystemBinary[
id: dSubTypeTSID, name: "dSubType", of: $DomainDomain, is: $DomainDomain, is1to1: FALSE];
END;
FakeTheNameHandle: PROC =
Sets up fake relation so that defaultNameHandle will work.
Must be called after RopeType defined.
BEGIN
fakeReln: Relation← DefineSystemRelation[DummyID, "fakeReln", FALSE];
defaultNameAttribute← DefineSystemField[fakeReln.systemTupleSet, "defaultNameAttribute", RopeType];
defaultNameAttribute.relation ← fakeReln;
defaultNameHandle← defaultNameAttribute.fh;
END;
FakeTheTypeAndLinkRelations: PROC =
The aType and aLink relations are tricky, to achieve better performance than the
obvious implementation. They are actually defined on two underlying properties,
the aTypeCodeProp and the aTypeEntityProp, which are surrogate attributes of the
attribute entities. When we do operations on aType or aLink, we must trap them,
interpreting aTypeCodeProp and aTypeEntityProp as follows:
(1) If aTypeEntityProp=NIL, then we have a non-entity-valued attribute, and the
aTypeCodeProp is the tid of the system DataType entity (e.g., RopeType, IntType).
(2) If aTypeEntityProp#NIL, then it references the domain that is the type of the
attribute, and aTypeCodeProp= 0 or -1 depending on whether it is linked or not linked.
Operations fetching or setting aType and aLink are trapped in the low-level procedures
GetValFromHandle and SetValFromHandle, so that they do not need to be checked
separately in GetF, SurrogateGetF, GetP, SetF, etc. The low level procedures have
only the handle for the attribute available, not the attribute itself; they thus must
do equality comparison to the aTypeIs.vHandle or aLinkIs.vHandle; so the handle is needed
merely for its unique pointer value, not for the DBStorage.FieldHandleObject it points to.
BEGIN
aType← DefineSystemRelation[
id: aTypeTSID, name: "aType", is1to1: TRUE];
aTypeOf← DefineSystemFieldObject["aTypeOf", $AttributeDomain].a;
aTypeOf.relation ← aType;
aTypeIs← DefineSystemField[aType.systemTupleSet, "aTypeIs", $DataTypeDomain];
aTypeIs.relation ← aType;
aTypeIs.fh← aTypeEntityProp.fh; -- so group scans work on type
aTypeOf.relation← aTypeIs.relation← aType;
aType.attributes← LIST[aTypeOf, aTypeIs];
aLink← DefineSystemRelation[
id: aLinkTSID, name: "aLink", is1to1: TRUE];
aLinkOf← DefineSystemFieldObject["aLinkOf", $AttributeDomain].a;
aLinkOf.relation ← aLink;
aLinkIs← DefineSystemField[aLink.systemTupleSet, "aLinkIs", IntType];
aLinkIs.relation ← aLink;
aLink.attributes← LIST[aLinkOf, aLinkIs];
aLinkOf.relation← aLinkIs.relation← aLink;
END;
DefineSystemBinary: PROC [
id: LONG CARDINAL, name: ROPE, of: DataType, is: DataType, is1to1: BOOLTRUE]
RETURNS [r: Relation, rOf, rIs: Attribute] =
Defines a binary system relation and attributes with types specified by of and is.
The system relation entity is given the tuple id specified, and attributes are allocated ids.
The attributes types are "of" and "is" respectively. The relation is given the specified name,
and the attributes are given the specified name postfixed by the strings "Of" and "Is".
If is1to1=TRUE, then relation is a "surrogate" relation, and the values are actually stored
as fields of the domain type of "of".
BEGIN
r← DefineSystemRelation[id, name, is1to1];
IF is1to1 THEN
The "is" attribute is actually a field of of's domain, not of the relation
BEGIN
ofDomain: Domain ← SystemDataTypeToDomain[of];
rOf← DefineSystemFieldObject[Rope.Concat[name, "Of"], of].a;
rOf.relation ← r;
rIs← DefineSystemField[ofDomain.systemTupleSet, Rope.Concat[name, "Is"], is, DefaultNameLength];
rIs.relation ← r;
END
ELSE
Normal attributes: fields of r.
BEGIN
rOf← DefineSystemField[r.systemTupleSet, Rope.Concat[name, "Of"], of];
rOf.relation ← r;
rIs← DefineSystemField[r.systemTupleSet, Rope.Concat[name, "Is"], is, DefaultNameLength];
rIs.relation ← r;
END;
r.attributes← LIST[rOf, rIs];
rOf.relation← rIs.relation← r;
END;
SystemDataTypeToDomain: PROC[type: DataType] RETURNS [d: Domain] =
BEGIN
SELECT type FROM
$DomainDomain => RETURN[DomainDomain];
$RelationDomain => RETURN[RelationDomain];
$AttributeDomain => RETURN[AttributeDomain];
$DataTypeDomain => RETURN[DataTypeDomain];
$IndexDomain => RETURN[IndexDomain];
$IndexFactorDomain => RETURN[IndexFactorDomain];
ENDCASE => ERROR DB.InternalError;
END;
DefineSystemRelation: PROC[id: LONG CARDINAL, name: ROPE, is1to1: BOOL] RETURNS[Relation] = TRUSTED
Defines a system relation.
BEGIN
r: Relation ← NEW[RelationObject];
t: TupleHandle ← DBStorage.ConsSystemTupleObject[];
IF id>MaxVTID THEN ERROR DB.InternalError;
t.tid← id;
t.name ← name;
r.name ← name;
r.isSystem ← TRUE;
r.is1to1 ← is1to1;
r.systemTupleSet ← DBStorage.CreateSystemTupleset[id];
systemTupleVec[Basics.LowHalf[id]]← t;
r.tuple ← t;
RETURN[r];
END;
DefineSystemDomain: PROC[id: LONG CARDINAL, name: ROPE] RETURNS[Domain] = TRUSTED
Defines a system domain or relation, according to the value of isDomain.
BEGIN
d: Domain ← NEW[DomainObject];
t: TupleHandle ← DBStorage.ConsSystemTupleObject[];
IF id>MaxVTID THEN ERROR DB.InternalError;
t.tid← id;
t.name ← name;
d.isSystem ← TRUE;
d.name ← name;
d.systemTupleSet ← DBStorage.CreateSystemTupleset[id];
systemTupleVec[Basics.LowHalf[id]]← t;
d.tuple ← t;
RETURN[d];
END;
DefineSystemField: PROC[
ts: DBStorage.SystemTuplesetHandle, name: ROPE, type: DataType, length: CARDINAL← 0] RETURNS[Attribute] = TRUSTED
Used as a subroutine to DefineSystemBinary and DefinePrivateProperty, to define a
field of domain or relation ts with the given name, type, and length if applicable.
BEGIN
f: Attribute; t: TupleHandle;
[f, t] ← DefineSystemFieldObject[name, type];
add a field to ts to hold values of this type:
f.fh← DBStorage.AddSystemField[ts, MakeFD[type, length,, t]];
RETURN[f]
END;
DefineSystemFieldObject: PROC[
name: ROPE, type: DataType] RETURNS[a: Attribute, t: TupleHandle] = TRUSTED
Used as a subroutine to DefineSystemField and DefineSystemBinary.
Defines the storage level object for a system field, though doesn't actually create the field.
BEGIN
a ← NEW[AttributeObject];
t ← DBStorage.ConsSystemTupleObject[];
t.tid← FirstAttributeID + attributeIDCount;
t.name ← name;
a.isSystem ← TRUE;
a.name ← name;
a.type ← type;
attributeIDCount← attributeIDCount+1;
IF FirstAttributeID+attributeIDCount>MaxVTID THEN ERROR DB.InternalError;
systemTupleVec[Basics.LowHalf[attributeIDCount+FirstAttributeID-1]]← t;
a.tuple ← t;
RETURN[a, t]
END;
DefineSystemEntity: PROC[
id: LONG CARDINAL, d: Domain, name: ROPE] RETURNS [Entity] = TRUSTED
Use only for DataTypes; creates a system entity object.
BEGIN
t: TupleHandle ← DBStorage.ConsSystemTupleObject[];
t.tid← id;
t.name ← name;
systemTupleVec[Basics.LowHalf[id]]← t;
RETURN[t]
END;
DefinePrivateProperty: PROC [
d: Domain, name: ROPE, type: DataType, length: INT← 0] RETURNS [Property] =
Adds an "invisible" new system relation which is actually a surrogate relation stored
as a field of the domain d. We use this instead of DefineSystemBinary when the client
doesn't actually need access to the relation, so we can just define the field alone.
This proc turns out to be implemented by calling DefineSystemField, but is logically
quite different since we are defining an "attribute" of a domain, not a relation. We fake
the call by pretending the domain is a relation (they are both TupleSets, the same type).
We add the fake attribute to the vAttributes list on the domain, so it can be used to
optimize SafeGetP and other operations.
BEGIN fakeAttribute: Attribute;
fakeAttribute← DefineSystemField[d.systemTupleSet, name, type, length];
fakeAttribute.domain ← d;
d.attributes← CONS[fakeAttribute, d.attributes];
fakeAttribute.domain← d;
RETURN[fakeAttribute]
END;
Operations on system tuples
SystemDomainSubset: PUBLIC PROC[d: Domain, lowName, highName: ROPE, segment: SegmentHandle, es: EntitySet] RETURNS [EntitySet] = TRUSTED
Domain d must be DomainDomain or RelationDomain. We implement an index scan on the
domain or relation index in the given segment, with names in the given range.
Note that there is no tuple set scan possible through domains or relations, because
the storage level provides no links through the system tuples.
Scans on the AttributeDomain, IndexDomain, and IndexFactorDomain are not currently
implemented. They must be accessed via system relations instead.
BEGIN
MakeIndexScan: PROC[indexToScan: DBStorage.IndexHandle] RETURNS[EntitySet] = TRUSTED
BEGIN
tsScan: DBStorage.IndexScanHandle;
[lowName, highName]← NCodeAndDefaultLimits[lowName, highName];
tsScan← DBStorage.OpenScanIndex[indexToScan, [lowName, highName, TRUE, TRUE], First ];
es.scan ← index;
es.indexScanHandle ← tsScan;
RETURN[es];
END;
SELECT d FROM
DomainDomain =>
es← MakeIndexScan[GetDomainIndex[segment]];
RelationDomain =>
es← MakeIndexScan[GetRelationIndex[segment]];
ENDCASE => ERROR DB.Error[NotImplemented];
RETURN[es];
END;
NCodeAndDefaultLimits: PROC [low, high: ROPE] RETURNS [newLow, newHigh: ROPE] = TRUSTED
Used by DomainSubset and RelationSubset to default limits on an index search. The
rules are: (1) if both high and low limits are NIL, the whole index is searched.
(2) if just the high limit is NIL, it defaults to the low limit, (3) any any case, we
must call NCode to convert to all upper case.
BEGIN
IF high=NIL THEN
IF low=NIL THEN {low← minfString; high← infString}
ELSE {low← NCode[DB.S2V[low]]; high← low}
ELSE
{low← NCode[DB.S2V[low]]; high← NCode[DB.S2V[high]]};
RETURN[low, high]
END;
END.