File: NutOpsImpl.mesa
Last edited by
Maxwell on: September 7, 1982 2:52 pm
Willie-Sue on: February 22, 1983 4:24 pm
Cattell on: July 28, 1983 10:37 am
Donahue, July 16, 1984 3:46:16 pm PDT
Widom, June 17, 1984 8:20:03 pm PDT
Butler, June 26, 1984 5:13:55 pm PDT
DIRECTORY
DB,
MBQueue,
MessageWindow,
NutOps,
Rope,
PrincOpsUtils,
ViewerClasses;
NutOpsImpl:
CEDAR
MONITOR
IMPORTS DB, Rope, PrincOpsUtils
EXPORTS NutOps
= BEGIN OPEN DB;
Viewer: TYPE = ViewerClasses.Viewer;
ROPE: TYPE = Rope.ROPE;
generally useful DB routines
IsSystemDomain:
PUBLIC
PROC[ name: Rope.
ROPE ]
RETURNS[
BOOLEAN ] = {
RETURN[
SELECT
TRUE
FROM
Rope.Equal[name, "DomainDomain"] => TRUE,
Rope.Equal[name, "RelationDomain"] => TRUE,
Rope.Equal[name, "DataTypeDomain"] => TRUE,
Rope.Equal[name, "AttributeDomain"] => TRUE,
Rope.Equal[name, "IndexDomain"] => TRUE,
Rope.Equal[name, "IndexFactorDomain"] => TRUE,
ENDCASE => FALSE ] };
IsSystemRelation:
PUBLIC
PROC[name: Rope.
ROPE]
RETURNS[
BOOLEAN] = {
RETURN[
SELECT
TRUE
FROM
Rope.Equal[name, "dSubType"] => TRUE,
Rope.Equal[name, "aRelation"] => TRUE,
Rope.Equal[name, "aType"] => TRUE,
Rope.Equal[name, "aUniqueness"] => TRUE,
Rope.Equal[name, "aLength"] => TRUE,
Rope.Equal[name, "aLink"] => TRUE,
Rope.Equal[name, "ifIndex"] => TRUE,
Rope.Equal[name, "ifAttribute"] => TRUE,
ENDCASE => FALSE ] };
IsSystemEntity:
PUBLIC
PROC[name: Rope.
ROPE]
RETURNS[
BOOLEAN] =
BEGIN
RETURN[ Rope.Equal[name, "Attribute"]
OR Rope.Equal[name, "DataType"]
OR Rope.Equal[name, "Domain"] OR Rope.Equal[name, "Relation"] ];
END;
AttributesOf:
PUBLIC
PROC[r: Relation]
RETURNS[AttributeList] =
{
IF Eq[r, dSubType]
THEN
RETURN[
LIST[dSubTypeIs, dSubTypeOf]];
IF Eq[r, aRelation] THEN RETURN[LIST[aRelationOf, aRelationIs]];
IF Eq[r, aType] THEN RETURN[LIST[aTypeOf, aTypeIs]];
IF Eq[r, aUniqueness] THEN RETURN[LIST[aUniquenessOf, aUniquenessIs]];
IF Eq[r, aLength] THEN RETURN[LIST[aLengthOf, aLengthIs]];
IF Eq[r, aLink] THEN RETURN[LIST[aLinkOf, aLinkIs]];
IF Eq[r, ifIndex] THEN RETURN[LIST[ifIndexOf, ifIndexIs]];
IF Eq[r, ifAttribute]
THEN
RETURN[
LIST[ifAttributeOf, ifAttributeIs]];
RETURN[VL2EL[GetPList[r, aRelationOf]]]};
FirstAttributeOf:
PUBLIC
PROC[r: Relation]
RETURNS[Attribute] =
BEGIN es: AttributeList← VL2EL[GetPList[r, aRelationOf]];
IF es=NIL THEN RETURN[NIL] ELSE RETURN[es.first]
END;
EntityValued:
PUBLIC
PROC [a: Attribute]
RETURNS[
BOOL] =
BEGIN type: Entity;
IF a=NIL OR Null[a] THEN RETURN[FALSE];
type← V2E[GetP[a, aTypeIs]];
SELECT type
FROM
IntType, RopeType, BoolType, RecordType, TimeType => RETURN[FALSE];
ENDCASE => RETURN[TRUE];
END;
GetUniquenessString:
PUBLIC
PROC[a: Attribute]
RETURNS[
ROPE] =
BEGIN u: Uniqueness;
IF Eq[a, dSubTypeIs] THEN RETURN["NonKey"];
IF Eq[a, dSubTypeOf] THEN RETURN["NonKey"];
IF Eq[a, aRelationOf] THEN RETURN["Key"];
IF Eq[a, aRelationIs] THEN RETURN["NonKey"];
IF Eq[a, aTypeOf] THEN RETURN["Key"];
IF Eq[a, aTypeIs] THEN RETURN["NonKey"];
IF Eq[a, aUniquenessOf] THEN RETURN["Key"];
IF Eq[a, aUniquenessIs] THEN RETURN["NonKey"];
IF Eq[a, aLengthOf] THEN RETURN["Key"];
IF Eq[a, aLengthIs] THEN RETURN["NonKey"];
IF Eq[a, aLinkOf] THEN RETURN["Key"];
IF Eq[a, aLinkIs] THEN RETURN["NonKey"];
IF Eq[a, ifIndexOf] THEN RETURN["Key"];
IF Eq[a, ifIndexIs] THEN RETURN["NonKey"];
IF Eq[a, ifAttributeOf] THEN RETURN["Key"];
IF Eq[a, ifAttributeIs] THEN RETURN["NonKey"];
u← V2U[GetP[a, aUniquenessIs]];
SELECT u
FROM
Key => RETURN["Key"];
KeyPart => RETURN["KeyPart"];
None => RETURN["NonKey"];
OptionalKey => RETURN["OptionalKey"];
ENDCASE => RETURN["???"];
END;
GetTuples:
PUBLIC
PROC[e: Entity, a: Attribute]
RETURNS [tl:
LIST
OF Relship] =
returns all the tuples that reference e in attribute a
{RETURN[RelshipSetToList[RelationSubset[GetRelation[a], LIST[[a, e]] ]]]};
GetRelation:
PUBLIC
PROC[a: Attribute]
RETURNS[r: Relation] =
finds a's relation
{RETURN[V2E[GetP[a, aRelationIs]]]};
GetRefAttributes:
PUBLIC
PROC[d: Domain]
RETURNS[al:
LIST
OF Attribute] =
returns all the attributes that can reference an entity from domain d
BEGIN
starRelation: Relation← DeclareRelation["*", SafeSegmentOf[d]];
starOf: Attribute;
starIs: Attribute;
starList: LIST OF Attribute;
starOf ← DeclareAttribute[r: starRelation, name: "of", type: AnyDomainType, version: OldOnly
! DB.Error => CHECKED { starOf ← NIL; CONTINUE } ];
starIs ← DeclareAttribute[r: starRelation, name: "is", type: AnyDomainType, version: OldOnly
! DB.Error => CHECKED { starIs ← NIL; CONTINUE } ];
starList ←
SELECT
TRUE
FROM
starOf = NIL AND starIs = NIL => NIL,
starIs = NIL => LIST[starOf],
starOf = NIL => LIST[starIs],
ENDCASE => LIST[starOf, starIs];
al← GetDomainRefAttributes[d];
al← AppendAttributes[al, starList];
END;
RemoveAttribute:
PUBLIC
PROC[a: Attribute, al: AttributeList]
RETURNS[AttributeList] =
destructively removes a from al
BEGIN alLast: AttributeList← NIL;
FOR alT: AttributeList← al, alT.rest
UNTIL alT=
NIL
DO
IF Eq[alT.first, a]
THEN
IF alLast=NIL THEN RETURN[alT.rest] -- was first element
ELSE {alLast.rest← alT.rest; RETURN[al]}; -- was another element
alLast← alT;
ENDLOOP;
RETURN[al] -- not found
END;
AppendAttributes:
PUBLIC
PROC [al1, al2: AttributeList]
RETURNS [al: AttributeList] =
BEGIN IF al1=NIL THEN RETURN [al2];
al← al1;
UNTIL al1.rest=
NIL
DO
al1← al1.rest ENDLOOP;
al1.rest← al2;
RETURN[al]
END;
RSetSize:
PUBLIC
PROC[rs: RelshipSet]
RETURNS[
INT] =
BEGIN
FOR size:
INT
IN [0..200)
DO
IF Null[NextRelship[rs]]
THEN
{ReleaseRelshipSet[rs]; RETURN[size]};
ENDLOOP;
ReleaseRelshipSet[rs];
RETURN[9999]; -- just tell 'im there are lots for now
END;
SetUpSegment:
PUBLIC
PROC[ segmentFile:
ROPE, seg:
DB.Segment, number:
NAT ← 0, makeReadOnly:
BOOL ←
FALSE ]
RETURNS [readOnly:
BOOL] =
TRUSTED {
A "foolproof" way to open a segment & transaction, regardless of whether the segment is already declared, doesn't exist, or already has a transaction open. Whenever an abort or failure occurs, just gives up.
readOnly ←
FALSE;
IF
DB.TransactionOf[seg] #
NIL
THEN
{readOnly← DB.GetSegmentInfo[seg].readOnly; RETURN};
DB.DeclareSegment[filePath: segmentFile, segment: seg, number: number, readonly: makeReadOnly, createIfNotFound: NOT makeReadOnly ];
DB.OpenTransaction[seg !
DB.Error =>
TRUSTED
{
SELECT code
FROM
ProtectionViolation =>
IF NOT makeReadOnly THEN {readOnly ← TRUE; CONTINUE} ELSE REJECT;
ENDCASE => REJECT } ];
IF readOnly
THEN
{ -- Try opening it readonly now; give up on a failure
DB.CloseTransaction[DB.TransactionOf[seg]]; -- DB has left the transaction open
DB.DeclareSegment[segmentFile, seg, number, TRUE, FALSE];
DB.OpenTransaction[seg] }
};
TryRestart:
PUBLIC
PROC[trans:
DB.Transaction]
RETURNS[success:
BOOL, failureReason:
ATOM] = {
segment: DB.Segment = GetSegment[trans];
fileName: ROPE = DB.GetSegmentInfo[segment].filePath;
{
ENABLE
DB.Failure => {failureReason ← what; success ←
FALSE;
GOTO Quit};
DB.AbortTransaction[trans];
now try to open the transaction
success ← FALSE;
FOR i:
INT
IN [0..5)
WHILE
NOT success
DO
DB.OpenTransaction[segment !
DB.Aborted => LOOP;
DB.Error => IF code = TransactionAlreadyOpen THEN CONTINUE];
success ← TRUE
ENDLOOP;
EXITS Quit => NULL } };
Do:
PUBLIC
PROC[ proc:
PROC[
REF
ANY], clientData:
REF
ANY ←
NIL]
RETURNS [outcome: NutOps.Outcome] = {
ENABLE
BEGIN
DB.Error => {outcome ← error; GOTO Quit};
DB.Failure => {outcome ← failure; GOTO Quit};
DB.Aborted => {outcome ← abort; GOTO Quit};
END;
outcome ← success;
proc[clientData]
EXITS Quit => NULL };
GetSegment:
PROC [t:
DB.Transaction]
RETURNS [seg:
DB.Segment] = {
Finds the first database segment associated with segment t. Note we assume all applications have only one segment per transaction right now.
segs: LIST OF DB.Segment← DB.GetSegments[];
FOR segs← segs, segs.rest
UNTIL segs=
NIL
DO
IF DB.TransactionOf[segs.first]=t THEN RETURN[segs.first] ENDLOOP;
RETURN[NIL]
};
SafeNameOf:
PUBLIC
PROC[e: Entity]
RETURNS [s:
ROPE] =
BEGIN
IF DB.Null[e] THEN RETURN["NEW"] ELSE RETURN [ DB.NameOf[e] ]
END;
SafeSegmentOf:
PUBLIC
PROC[e: EntityOrRelship]
RETURNS [s: Segment] =
BEGIN
IF DB.Null[e] THEN RETURN[NIL] ELSE RETURN [ DB.SegmentOf[e] ]
END;
SafeDomainOf:
PUBLIC
PROC[e: Entity]
RETURNS [s: Domain] =
BEGIN
IF DB.Null[e] THEN RETURN[NIL] ELSE RETURN [ DB.DomainOf[e] ]
END;
END.
Changes since October 82:
Cattell October 13, 1982 9:28 am: Save and Reset buttons should Fork.
Cattell December 1, 1982 4:29 pm: Should call GetRope instead of GetToken for 2nd DBShow argument.
Cattell June 22, 1983 5:08 pm:
Butler June 26, 1984:
Updated to comply with new organization of Nut and Squirrel