<> <> <> <> <> <> <> <> <> DIRECTORY CardTable, DBCommon, DBStorage, DBDefs, DB, DBModel, DBModelPrivate, Rope, SymTab; DBModelDomainImpl: CEDAR PROGRAM IMPORTS CardTable, DBStorage, DB, DBModelPrivate, Rope, SymTab EXPORTS DBModel, DBModelPrivate SHARES Rope = BEGIN OPEN DBCommon, DBDefs; <> 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]; <> <<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] }; <> nameHandle, indexHandle, superHandle, nameHandleHandle: DBStorage.FieldHandle; <> <> DeclareDomain: 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] }; d _ LookupDomain[name, segment]; IF d # NIL THEN RETURN[d]; <> 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]; <> d _ AddToCache[t]; <> 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 <> tuple: TupleHandle = GetNamedTuple[domainIndex, name]; IF tuple = NIL THEN RETURN[NIL]; -- it's not to be found <> 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]; <> 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] = { <> 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] = { <> IF d = NIL THEN RETURN; CheckDomainKey[d]; IF NOT d.detailsKnown THEN ReadDomain[d]; <> 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; <> d.superType _ NIL; NullifyTupleField[d.tupleSet, superHandle]; <> 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; <> BEGIN DBStorage.DestroyIndex[d.index]; DBStorage.DestroyTuple[d.index] END; <> DBModelPrivate.DestroyStoredRelations[d]; DBModelPrivate.DestroySurrogates[d]; DBStorage.DeleteFromIndex[segmentHandle.indices[DBCommon.domainIndex], d.name, d.tupleSet]; DBStorage.DestroyTuple[d.tupleSet]; <> 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] = { <=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] = { <> 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 { <> 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] = { <> 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]; <> <> SetTupleField[is.tupleSet, superHandle, of.tupleSet]; is.superType _ of; <> 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] = { <> 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] = { <> yes _ DBStorage.TupleForField[d.tupleSet, superHandle] = NIL }; TypeForDomain: PUBLIC PROC[d: Domain] RETURNS[type: TypeCode] = { CheckDomainKey[d]; RETURN[[code: d.tupleSet.tid]] }; <> 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] = <> 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] = <= 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 <> DBStorage.DeleteFromIndex[e.domain.index, e.name, e.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 }; END.