Definition of the structure of Domains in the Database
STSVecType: TYPE = ARRAY[1..DBStorage.MaxSystemTupleID] OF TupleHandle;
systemTupleVec: REF STSVecType ← NEW[STSVecType ← ALL[NIL]];
DomainTupleSet: PUBLIC DBStorage.SystemTuplesetHandle;
DomainDomain: PUBLIC DBCommon.TupleHandle;
RelationDomain: PUBLIC DBCommon.TupleHandle;
RelationTupleSet: PUBLIC DBStorage.SystemTuplesetHandle;
IndexTupleSet: PUBLIC DBStorage.SystemTuplesetHandle;
IndexDomain: PUBLIC DBCommon.TupleHandle;
SetSystemTable:
PUBLIC PROC[tid:
TID]
RETURNS[tupleSet: DBStorage.SystemTuplesetHandle, tuple: DBCommon.TupleHandle] =
TRUSTED {
tupleSet ← DBStorage.CreateSystemTupleset[tid];
tuple ← DBStorage.ConsSystemTupleObject[];
tuple.tid ← tid;
systemTupleVec[tid] ← tuple
};
InitializeDomainSchema:
PUBLIC PROC[] =
TRUSTED {
DBStorage.SetSystemTupleTable[systemTupleVec];
[DomainTupleSet, DomainDomain] ← SetSystemTable[DBModelPrivate.DomainTSID];
[IndexTupleSet, IndexDomain] ← SetSystemTable[DBModelPrivate.IndexTSID];
[RelationTupleSet, RelationDomain] ← SetSystemTable[DBModelPrivate.RelationTSID];
The DomainDomain tuples are tuplesets with the following additional fields:
1. the name of the domain
2. the index ID of the index on the names of entities in the domain
3. the superType of the domain (a TID that may be empty),
4. the field handle to be used when accessing entities in the tupleset
[] ← DBStorage.AddSystemField[DomainTupleSet, DBModelPrivate.TupleSetDescriptor];
nameHandle ← DBStorage.AddSystemField[DomainTupleSet, DBModelPrivate.NameDescriptor];
indexHandle ← DBStorage.AddSystemField[DomainTupleSet, DBStorage.FieldDescriptor[Group[groupID: IndexDomain]]];
superHandle ← DBStorage.AddSystemField[DomainTupleSet, DBStorage.FieldDescriptor[Group[groupID: DomainDomain]]];
nameHandleHandle ← DBStorage.AddSystemField[DomainTupleSet, DBModelPrivate.HandleDescriptor] };
Operations on Domains
DeclareDomain:
PUBLIC
PROC [name:
ROPE, segment: Segment]
RETURNS [d: Domain] = {
Creates a domain of this name or fetches it if it already exists.
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[segment];
domainIndex: DBStorage.IndexHandle = sh.indices[DBCommon.domainIndex];
AddToCache:
PROC[tuple: TupleHandle]
RETURNS[d: Domain] = {
cachedTuple: TupleHandle = DBModelPrivate.CopyTupleHandle[tuple];
domainEntry: REF DomainObject = NEW[DomainObject ← [key: sh.key, segment: segment, name: name, tupleSet: cachedTuple]];
d ← domainEntry;
[] ← SymTab.Store[x: sh.domainTable, key: name, val: domainEntry];
[] ← CardTable.Store[x: sh.domainsByTID, key: tuple.tid, val: domainEntry];
RETURN[d]
};
d ← LookupDomain[name, segment];
IF d # NIL THEN RETURN[d];
Create a new domain.
BEGIN
t: TupleHandle = DBStorage.CreateSystemPageTuple[x: DomainTupleSet, y: NIL, s: segment];
i: TupleHandle = DBStorage.CreateSystemPageTuple[x: IndexTupleSet, y: t, s: segment];
DBStorage.CreateTupleset[t];
DBStorage.CreateIndex[i];
DBStorage.WriteVarByte[t, nameHandle, name];
DBStorage.InsertIntoIndex[domainIndex, name, t];
SetTupleField[t, indexHandle, i];
Add the tuple to the domain cache for the segment
d ← AddToCache[t];
create the name field for the entities of this domain
d.entityNameHandle ← DBStorage.AddField[t, DBModelPrivate.NameDescriptor];
DBModelPrivate.SetFieldField[t, nameHandleHandle, d.entityNameHandle];
d.index ← CopyTupleHandle[i];
d.detailsKnown ← TRUE;
sh.schemaUpdated ← TRUE;
RETURN[d]
END
};
LookupDomain:
PUBLIC
PROC [name:
ROPE, segment: Segment]
RETURNS [d: Domain] = {
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[segment];
domainIndex: DBStorage.IndexHandle = sh.indices[DBCommon.domainIndex];
AddToCache:
PROC[tuple: TupleHandle]
RETURNS[d: Domain] = {
cachedTuple: TupleHandle = DBModelPrivate.CopyTupleHandle[tuple];
domainEntry: REF DomainObject = NEW[DomainObject ← [key: sh.key, segment: segment, name: name, tupleSet: cachedTuple]];
d ← domainEntry;
[] ← SymTab.Store[x: sh.domainTable, key: name, val: domainEntry];
[] ← CardTable.Store[x: sh.domainsByTID, key: tuple.tid, val: domainEntry];
RETURN[d]
};
val: REF ANY = SymTab.Fetch[x: sh.domainTable, key: name].val;
d ← NARROW[val];
IF d # NIL THEN RETURN[d];
BEGIN
See if you can find it in the index for the DomainDomain
tuple: TupleHandle = GetNamedTuple[domainIndex, name];
IF tuple = NIL THEN RETURN[NIL]; -- it's not to be found
It's in the database, but not in the cache. Cache it; none of the details of the entry are computed yet
d ← AddToCache[tuple];
END };
ReadDomain:
PUBLIC PROC[d: Domain] = {
d.index ← CopyTupleHandle[GetTupleField[d.tupleSet, indexHandle]];
d.entityNameHandle ← DBModelPrivate.GetFieldField[d.tupleSet, nameHandleHandle];
d.detailsKnown ← TRUE
};
CheckForNull:
PUBLIC
PROC[t: TupleHandle] = {
IF DBStorage.NullTuple[t] THEN DB.Error[NullifiedArgument] };
CopyTupleHandle:
PUBLIC PROC[t: TupleHandle]
RETURNS[new: TupleHandle] = {
new ← DBStorage.ConsSystemTupleObject[];
new.tid ← t.tid; new.cacheHint ← t.cacheHint };
EmptyTupleSet:
PUBLIC
PROC[ts: DBStorage.TuplesetHandle]
RETURNS[yes:
BOOL] = {
yes ← DBStorage.EmptyTupleSet[ts] };
GetNamedTuple: PUBLIC PROC[index: DBStorage.IndexHandle, name: ROPE] RETURNS[tuple: TupleHandle] = { tuple ← DBStorage.TupleForKey[index, name] };
SetTupleField:
PUBLIC PROC[t: TupleHandle, f: DBStorage.FieldHandle, val: TupleHandle] = {
DBStorage.SetTupleField[t, f, val] };
GetTupleField: PUBLIC PROC[t: TupleHandle, f: DBStorage.FieldHandle] RETURNS[val: TupleHandle] = { val ← DBStorage.ReadTID[t, f] };
NullifyTupleField:
PUBLIC
PROC[t: TupleHandle, f: DBStorage.FieldHandle] = {
DBStorage.WriteTIDNil[t, f] };
GetRopeField: PUBLIC PROC[t: TupleHandle, f: DBStorage.FieldHandle] RETURNS[val: Rope.ROPE] = { val ← DBStorage.ReadVarByte[t, f] };
SetRopeField:
PUBLIC
PROC[t: TupleHandle, f: DBStorage.FieldHandle, val: Rope.
ROPE] = {
IF val = NIL THEN val ← "";
DBStorage.WriteVarByte[t, f, val] };
CheckDomainKey:
PUBLIC PROC[d: Domain] = {
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[d.segment];
IF sh.key # d.key THEN ERROR DB.Error[IllegalDomain] };
CompatibleTypes:
PUBLIC
PROC[d: Domain, type: TypeCode]
RETURNS[yes:
BOOL] = {
WHILE
TRUE
DO
IF d.tupleSet.tid = type.code
THEN
RETURN[
TRUE];
is the subtype the type we're looking for?
IF NOT d.superTypeKnown THEN SetSuperType[d];
IF d.superType = NIL THEN RETURN[FALSE]; -- d has no super type
d ← d.superType -- go up the chain
ENDLOOP };
SetSuperType:
PROC[d:
REF DomainObject] = {
Compute the SuperType of the domain d
superTuple: TupleHandle = GetTupleField[d.tupleSet, superHandle];
d.superType ← IF superTuple = NIL THEN NIL ELSE TupleToDomain[superTuple, d.segment];
d.superTypeKnown ← TRUE
};
TupleToDomain:
PUBLIC PROC[t: TupleHandle, segment: Segment, name: Rope.
ROPE ←
NIL]
RETURNS[d: Domain] = {
IF t=NIL THEN RETURN[NIL];
BEGIN
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[segment];
AddToCache:
PROC[tuple: TupleHandle]
RETURNS[d: Domain] = {
cachedTuple: TupleHandle = DBModelPrivate.CopyTupleHandle[tuple];
domainEntry: REF DomainObject = NEW[DomainObject ← [key: sh.key, segment: segment, name: name, tupleSet: cachedTuple]];
d ← domainEntry;
[] ← SymTab.Store[x: sh.domainTable, key: name, val: domainEntry];
[] ← CardTable.Store[x: sh.domainsByTID, key: t.tid, val: domainEntry];
RETURN[d]
};
d ← NARROW[CardTable.Fetch[sh.domainsByTID, t.tid].val];
IF d # NIL THEN RETURN;
IF name = NIL THEN name ← GetRopeField[t, nameHandle];
d ← AddToCache[t]
END
};
DestroyDomain:
PUBLIC
PROC [d: Domain] = {
Destroys a domain, all its entities, and all relationships that reference entities in d. To destroy a domain, we remove it from the domain from the SubType list of its SuperType, destroy all of the entities in the domain and then destroy all of the relations that had fields of the domain type
IF d = NIL THEN RETURN;
CheckDomainKey[d];
IF NOT d.detailsKnown THEN ReadDomain[d];
If d still has remaining subtypes, then it cannot be destroyed
BEGIN
subs: DomainSet = SubTypes[d];
IF NextDomain[subs] #
NIL
THEN {
ReleaseDomainSet[subs];
ERROR DB.Error[NotImplemented] }; -- must destroy the domain's subdomains first!
ReleaseDomainSet[subs]
END;
BEGIN
segmentHandle: SegmentHandle = DBModelPrivate.SegmentToHandle[d.segment];
TID: DBCommon.TID = d.tupleSet.tid;
remove connection to any supertype
d.superType ← NIL; NullifyTupleField[d.tupleSet, superHandle];
Destroy all of the entities in the domain
BEGIN
scanHandle: DBStorage.TuplesetScanHandle = DBStorage.OpenScanTupleset[d.tupleSet, First];
FOR t: TupleHandle ← DBStorage.NextScanTupleset[scanHandle], DBStorage.NextScanTupleset[scanHandle]
UNTIL t =
NIL
DO
DBModelPrivate.Unlink[t, d];
SetRopeField[t, d.entityNameHandle, NIL];
DBStorage.DestroyTuple[t]
ENDLOOP;
DBStorage.CloseScanTupleset[scanHandle]
END;
Destroy the index on the domain
BEGIN
DBStorage.DestroyIndex[d.index];
DBStorage.DestroyTuple[d.index]
END;
Destroy all of the relations that reference the domain and the domain tuple itself
DBModelPrivate.DestroyStoredRelations[d];
DBModelPrivate.DestroySurrogates[d];
DBStorage.DeleteFromIndex[segmentHandle.indices[DBCommon.domainIndex], d.name, d.tupleSet];
DBStorage.DestroyTuple[d.tupleSet];
Finally, remove the information from the cache and remember that the schema has been updated
segmentHandle.schemaUpdated ← TRUE;
[] ← SymTab.Delete[segmentHandle.domainTable, d.name];
[] ← CardTable.Delete[segmentHandle.domainsByTID, TID];
d.key ← 0; -- this entry should no longer be used
END
};
DomainsByName:
PUBLIC
PROC [segment: Segment, lowName, highName:
ROPE, start: FirstLast]
RETURNS[ds: DomainSet] = {
Provides a domain set that enumerates domains in the given segment. If lowName and highName are non-NIL, enumerates only those domains whose name is lexicographically >=lowName and <=highName. If only highName is NIL, it defaults to lowName, i.e. we will search for the domain whose name exactly equals lowName.
iScan: DBStorage.IndexHandle = DBModelPrivate.SegmentToHandle[segment].indices[DBCommon.domainIndex];
IF highName = NIL THEN highName ← lowName;
ds ← NEW[DomainSetObject ← [segment: segment, variant: index[scanHandle: DBStorage.OpenScanIndex[iScan, [lowerBound: lowName, upperBound: highName, includeLowerBound: TRUE, includeUpperBound: TRUE, lowerBoundInfinity: lowName = NIL, upperBoundInfinity: highName = NIL], start]]]];
RETURN[ds] };
typeTuple: TupleHandle ← DBStorage.ConsSystemTupleObject[];
TypeToDomain:
PUBLIC
PROC[type: DBDefs.TypeCode, segment: Segment]
RETURNS[d: Domain] = {
Turn the TID into a tuple handle and use TupleToDomain
typeTuple.tid ← type.code; typeTuple.cacheHint ← NIL;
d ← TupleToDomain[typeTuple, segment]
};
NameFromIndexKey:
PUBLIC PROC[key: DBCommon.IndexKey]
RETURNS[name: Rope.
ROPE] =
TRUSTED {
IF key = NIL OR key.length = 0 THEN RETURN[NIL];
BEGIN
indexValue: Rope.Text ← Rope.NewText[key.length];
FOR i: CARDINAL IN [0..key.length) DO indexValue.text[i] ← key.text[i] ENDLOOP;
indexValue.length ← key.length;
RETURN[indexValue]
END
};
NextDomain:
PUBLIC
PROC [ds: DomainSet]
RETURNS [d: Domain] =
TRUSTED {
IF ds = NIL THEN RETURN[NIL];
WITH ds: ds
SELECT
FROM
index =>
BEGIN
name: Rope.ROPE = NameFromIndexKey[DBStorage.NextScanKey[ds.scanHandle]];
tuple: DBCommon.TupleHandle = IF name # NIL THEN DBStorage.ThisScanTuple[ds.scanHandle] ELSE NIL;
IF tuple # NIL THEN d ← TupleToDomain[tuple, ds.segment, name]
END;
group => {
tuple: DBCommon.TupleHandle = DBStorage.NextInGroup[ds.scanHandle];
IF tuple # NIL THEN d ← TupleToDomain[tuple, ds.segment] }
ENDCASE };
PrevDomain:
PUBLIC
PROC [ds: DomainSet]
RETURNS [d: Domain] =
TRUSTED {
IF ds = NIL THEN RETURN[NIL];
WITH ds: ds
SELECT
FROM
index =>
BEGIN
name: Rope.ROPE = NameFromIndexKey[DBStorage.PrevScanKey[ds.scanHandle]];
tuple: DBCommon.TupleHandle = IF name # NIL THEN DBStorage.ThisScanTuple[ds.scanHandle] ELSE NIL;
IF tuple # NIL THEN d ← TupleToDomain[tuple, ds.segment, name]
END;
group => {
tuple: DBCommon.TupleHandle = DBStorage.PrevInGroup[ds.scanHandle];
IF tuple # NIL THEN d ← TupleToDomain[tuple, ds.segment] }
ENDCASE };
ReleaseDomainSet:
PUBLIC
PROC [ds: DomainSet] =
TRUSTED {
Should be called when client is finished with a DomainSet.
IF ds = NIL THEN RETURN;
WITH ds: ds
SELECT
FROM
index => { DBStorage.CloseScanIndex[ds.scanHandle]; ds.scanHandle ← NIL };
group => { DBStorage.CloseScanGroup[ds.scanHandle]; ds.scanHandle ← NIL }
ENDCASE };
EmptyDomain:
PROC[d: Domain]
RETURNS[ yes:
BOOL ] = {
scanHandle: DBStorage.TuplesetScanHandle = DBStorage.OpenScanTupleset[d.tupleSet, First];
nextTuple: TupleHandle = DBStorage.NextScanTupleset[scanHandle];
DBStorage.CloseScanTupleset[scanHandle];
RETURN[nextTuple = NIL] };
DeclareSubType:
PUBLIC
PROC [of, is: Domain] = {
Check that sub (is) does not already have a supertype, that the supertype isn't compatible with the subtype (i.e., you're not about to introduce a cycle) and that supertype is empty.
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[of.segment];
CheckDomainKey[of]; CheckDomainKey[is];
IF of.segment # is.segment THEN ERROR DB.Error[IllegalSuperType];
IF NOT is.superTypeKnown THEN SetSuperType[is];
IF is.superType #
NIL
THEN
IF Rope.Equal[is.superType.name, of.name] THEN RETURN
ELSE ERROR DB.Error[IllegalSuperType];
IF CompatibleTypes[is, TypeForDomain[of]] THEN ERROR DB.Error[IllegalSuperType];
IF
NOT EmptyDomain[of]
THEN
ERROR
DB.Error[NotImplemented];
Currently can't define subdomain if super already has entries
Set the supertype of the domain is to be the domain of and add the domain is to the subtype list of domain of
SetTupleField[is.tupleSet, superHandle, of.tupleSet];
is.superType ← of;
Record the fact that the schema has been changed
sh.schemaUpdated ← TRUE;
};
DestroySubType:
PUBLIC
PROC [of, is: Domain] = {
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[of.segment];
CheckDomainKey[of]; CheckDomainKey[is];
IF of.segment # is.segment THEN ERROR DB.Error[IllegalSuperType];
IF NOT is.superTypeKnown THEN SetSuperType[is];
IF is.superType = NIL OR is.superType # of THEN ERROR DB.Error[IllegalSuperType];
IF NOT EmptyDomain[is] THEN ERROR DB.Error[NotImplemented];
NullifyTupleField[is.tupleSet, superHandle];
is.superType ← NIL;
sh.schemaUpdated ← TRUE };
SuperType:
PUBLIC
PROC [d: Domain]
RETURNS [super: Domain] = {
CheckDomainKey[d];
IF NOT d.superTypeKnown THEN SetSuperType[d];
super ← d.superType };
SubTypes:
PUBLIC
PROC [d: Domain]
RETURNS[subs: DomainSet] = {
Returns the subtypes of a given domain (if any have been previously defined using DeclareSubType)
CheckDomainKey[d];
BEGIN
scanHandle: DBStorage.GroupScanHandle = DBStorage.OpenScanGroup[d.tupleSet, superHandle, First];
subs ← NEW[DomainSetObject ← [segment: d.segment, variant: group[scanHandle]]]
END };
NoSubtypes:
PUBLIC
PROC[d: Domain]
RETURNS[yes:
BOOL] = {
This quickly checks for no subtypes
yes ← DBStorage.TupleForField[d.tupleSet, superHandle] = NIL };
TypeForDomain:
PUBLIC
PROC[d: Domain]
RETURNS[type: TypeCode] = {
CheckDomainKey[d];
RETURN[[code: d.tupleSet.tid]] };
Operations on Entities
DeclareEntity:
PUBLIC
PROC[d: Domain, name:
ROPE, newOnly:
BOOL ←
FALSE]
RETURNS [e: Entity] =
BEGIN
CheckDomainKey[d];
e ← LookupEntity[d, name];
IF e # NIL THEN IF newOnly THEN ERROR DB.Error[AlreadyExists] ELSE RETURN[e];
BEGIN
tuple: TupleHandle = DBStorage.CreateTuple[x: d.tupleSet];
DBStorage.InsertIntoIndex[d.index, name, tuple];
DBStorage.WriteVarByte[tuple, d.entityNameHandle, name];
e ← NEW[EntityObject ← [name: name, domain: d, tuple: tuple]]
END
END;
LookupEntity:
PUBLIC
PROC[d: Domain, name:
ROPE]
RETURNS [e: Entity] =
Checks to see if the entity already exists. If so, it returns it, if not, it returns NIL.
BEGIN
tuple: DBCommon.TupleHandle;
IF NOT d.detailsKnown THEN ReadDomain[d];
tuple ← GetNamedTuple[d.index, name];
IF tuple = NIL THEN RETURN[NIL];
RETURN[NEW[EntityObject ← [name: name, domain: d, tuple: tuple]]]
END;
DomainSubset:
PUBLIC
PROCEDURE[d: Domain, lowName, highName:
ROPE, start: FirstLast]
RETURNS [es: EntitySet] =
Used with NextEntity to index through entities in a domain. If lowName or highName are non-NIL, enumerates only those entities whose name is lexicographically >= lowName and <= highName, and the enumeration is sorted. In this case, we create an "index" variant of EntitySetObject. If both are NIL, we create an unindexed (tupleSet variant) EntitySet.
BEGIN
CheckDomainKey[d];
IF NOT d.detailsKnown THEN ReadDomain[d];
BEGIN
-- Search using index
IF highName = NIL THEN highName ← lowName;
es ← NEW[EntitySetObject ← [domain: d, scanHandle: DBStorage.OpenScanIndex[d.index, [lowerBound: lowName, upperBound: highName, includeLowerBound: TRUE, includeUpperBound: TRUE, lowerBoundInfinity: lowName = NIL, upperBoundInfinity: highName = NIL], start]]];
END
END;
NextEntity:
PUBLIC
PROCEDURE[es: EntitySet]
RETURNS[e: Entity] =
TRUSTED {
IF es=NIL THEN RETURN[NIL];
CheckDomainKey[es.domain];
BEGIN
name: Rope.ROPE = NameFromIndexKey[DBStorage.NextScanKey[es.scanHandle]];
tuple: TupleHandle = IF name # NIL THEN DBStorage.ThisScanTuple[es.scanHandle] ELSE NIL;
IF tuple = NIL THEN RETURN[NIL];
RETURN[NEW[ EntityObject ← [domain: es.domain, name: name, tuple: tuple]]]
END };
PrevEntity:
PUBLIC
PROCEDURE[es: EntitySet]
RETURNS[e: Entity] =
TRUSTED {
IF es=NIL THEN RETURN[NIL];
CheckDomainKey[es.domain];
BEGIN
name: Rope.ROPE = NameFromIndexKey[DBStorage.PrevScanKey[es.scanHandle]];
tuple: TupleHandle = IF name # NIL THEN DBStorage.ThisScanTuple[es.scanHandle] ELSE NIL;
IF tuple = NIL THEN RETURN[NIL];
RETURN[NEW[ EntityObject ← [domain: es.domain, name: name, tuple: tuple]]]
END };
ReleaseEntitySet:
PUBLIC
PROCEDURE[es: EntitySet] =
BEGIN
IF es=NIL THEN RETURN;
IF es.scanHandle #
NIL
THEN {
DBStorage.CloseScanIndex[es.scanHandle]; es.scanHandle ← NIL };
END;
DestroyEntity:
PUBLIC
PROC[e: Entity] =
BEGIN
CheckDomainKey[e.domain]; -- make sure it's a legal entity first
CheckForNull[e.tuple];
DBModelPrivate.Unlink[e.tuple, e.domain]; -- destroy all relationships referring to the entity
Destroy the name index entry
DBStorage.DeleteFromIndex[e.domain.index, e.name, e.tuple];
Destroy the entity by setting the name field to NIL and then destroying the tuple
SetRopeField[e.tuple, e.domain.entityNameHandle, NIL];
DBStorage.DestroyTuple[e.tuple];
END;
CopyEntity:
PUBLIC
PROC[e: Entity]
RETURNS[Entity] = {
IF e = NIL THEN RETURN[NIL];
RETURN[NEW[EntityObject ← [domain: e.domain, name: e.name, tuple: CopyTupleHandle[e.tuple]]]] };
DomainEq:
PUBLIC
PROC [d1, d2: Domain]
RETURNS[
BOOL] = {
IF d1 = NIL THEN RETURN[d2 = NIL];
IF d2 = NIL THEN RETURN[FALSE];
CheckDomainKey[d1]; CheckDomainKey[d2];
RETURN[d1^ = d2^] };
NullDomain:
PUBLIC
PROC[d: Domain]
RETURNS[
BOOLEAN] = {
IF d = NIL THEN RETURN[TRUE];
BEGIN
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[d.segment];
RETURN[d.key # sh.key]
END };
NullEntity:
PUBLIC
PROC[e: Entity]
RETURNS[yes:
BOOL] = {
IF e = NIL THEN RETURN[TRUE];
IF DBStorage.NullTuple[e.tuple] THEN RETURN[TRUE];
BEGIN
d: Domain = e.domain;
sh: SegmentHandle = DBModelPrivate.SegmentToHandle[d.segment];
RETURN[d.key # sh.key]
END };
EntityEq:
PUBLIC
PROC[e1: Entity, e2: Entity]
RETURNS[yes:
BOOL] = {
IF NullEntity[e1] THEN RETURN[NullEntity[e2]];
IF NullEntity[e2] THEN RETURN[NullEntity[e1]];
RETURN[DomainEq[e1.domain, e2.domain] AND e1.tuple.tid = e2.tuple.tid]
};
EntityInfo:
PUBLIC
PROC [e: Entity]
RETURNS [name:
ROPE, domain: Domain] = {
IF e = NIL THEN RETURN;
CheckDomainKey[e.domain];
RETURN[e.name, e.domain] };
ToUnderType:
PUBLIC
PROC[e: Entity] = {
IF e = NIL THEN RETURN;
CheckDomainKey[e.domain];
CheckForNull[e.tuple];
BEGIN
domaintuple: TupleHandle = DBStorage.ReadTupleset[e.tuple];
IF domaintuple.tid = e.domain.tupleSet.tid THEN RETURN;
e.domain ← TupleToDomain[domaintuple, e.domain.segment]
END };
ChangeName:
PUBLIC
PROC [of: Entity, to: Rope.
ROPE] ~ {
IF of = NIL THEN RETURN;
IF to = NIL THEN ERROR DB.Error[NILArgument];
CheckDomainKey[of.domain];
CheckForNull[of.tuple];
BEGIN
d: Domain = of.domain;
IF GetNamedTuple[d.index, to] # NIL THEN DB.Error[AlreadyExists];
DBStorage.DeleteFromIndex[d.index, of.name, of.tuple];
DBStorage.InsertIntoIndex[d.index, to, of.tuple];
DBStorage.WriteVarByte[of.tuple, d.entityNameHandle, to];
of.name ← to
END
};