WalnutSchemaImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Willie-Sue, May 22, 1986 4:59:34 pm PDT
Donahue, April 10, 1986 2:49:04 pm PST
Types and entities in the Walnut message database
Last Edited by: Willie-Sue, January 4, 1985 9:05:15 am PST
Last Edited by: Wert, August 31, 1984 7:38:03 pm PDT
Last Edited by: Donahue, February 2, 1985 9:37:11 am PST
(Added NewMail and Archive log position info for restart)
(Changed to be consistent with new WalnutSchema)
DIRECTORY
BasicTime USING [GMT, nullGMT, OutOfRange],
Convert USING [TimeFromRope],
DB USING [Boolean, CreateRelship, Error, FieldSpec, FirstRelship, DeclareDomain, DeclareIndex, DeclareProperty, DeclareRelation, GetF, Integer, L2F, L2FS, L2VS, SetF, String, T2V, Time, TypeForDomain, TypeSpec, V2T,
Domain, FieldSequence, Index, Relation, Relship, TypeCode, ValueSequence],
IO,
Rope USING [ROPE, Cat],
WalnutDefs USING [Error, SchemaMismatch, Segment],
WalnutRoot USING [CommitAndContinue],
WalnutSchema;
WalnutSchemaImpl: CEDAR PROGRAM
IMPORTS Convert, DB, IO, Rope, WalnutDefs, WalnutRoot
EXPORTS WalnutSchema, WalnutDefs
= BEGIN
OPEN WalnutSchema;
Types
GMT: TYPE = BasicTime.GMT;
ROPE: TYPE = Rope.ROPE;
Signals and Errors
SchemaMismatch: PUBLIC SIGNAL[explanation: ROPENIL] = CODE;
VersionMismatch: PUBLIC SIGNAL[explanation: ROPENIL] = CODE;
Error: PUBLIC SIGNAL [who, code: ATOM, explanation: ROPENIL] = CODE;
Variables
schemaVersionDate: GMT = Convert.TimeFromRope["April 15, 1986 2:14:01 pm PST"];
Global Relations - one each per database
gRootInfo: PUBLIC DB.Relation;
gRootInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "RootFileStamp", type: DB.Time],
[name: "gRootFileKey", type: DB.String, lengthHint: 20],
[name: "MailFor", type: DB.String, lengthHint: 20]
]];
gLogInfo: PUBLIC DB.Relation;
gLogInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "LogFileID", type: DB.Integer],
[name: "OpInProgressPos", type: DB.Integer],
[name: "FirstDestroyedMsgPos", type: DB.Integer],
[name: "BytesInDestroyedMsgs", type: DB.Integer],
[name: "TimeOfLastScavenge", type: DB.Time]
]];
gParseLogInfo: PUBLIC DB.Relation;
gParseLogInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "ParseLogInProgress", type: DB.Boolean],
[name: "ParseLogPos", type: DB.Integer]
]];
gExpungeInfo: PUBLIC DB.Relation;
gExpungeLogInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "LogExpungePhase", type: DB.Integer],
[name: "gExpungeFileID", type: DB.Integer],
[name: "CurrentLogPos", type: DB.Integer],
[name: "TempLogPos", type: DB.Integer],
[name: "TimeOfLastExpunge", type: DB.Time]
]];
gNewMailInfo: PUBLIC DB.Relation;
gNewMailInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "NewMailLogLength", type: DB.Integer],
[name: "CopyNewMailLogPos", type: DB.Integer],
[name: "AcceptNewMailLogPos", type: DB.Integer],
[name: "AddingServerMsgs", type: DB.Boolean],
[name: "LastNewMailTimeStamp", type: DB.Time]
]];
gReadArchiveInfo: PUBLIC DB.Relation;
gReadArchiveInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "ReadArchiveLogPos", type: DB.Integer],
[name: "CopyReadArchiveLogPos", type: DB.Integer]
]];
gVersionInfo: PUBLIC DB.Relation;
gVersionInfoFields: DB.FieldSpec =
DB.L2FS[LIST[
[name: "MsgCount", type: DB.Integer],
[name: "MsgSetCount", type: DB.Integer],
[name: "MsgSetsVersion", type: DB.Integer]
]];
Global Domains
MsgDomain: PUBLIC DB.Domain;
MsgTypeProc: PROC[] RETURNS[DB.TypeCode] =
{ RETURN[DB.TypeForDomain[MsgDomain]] };
MsgType: DB.TypeSpec = [indirect[MsgTypeProc]];
MsgSetDomain: PUBLIC DB.Domain;
MsgSetTypeProc: PROC[] RETURNS[DB.TypeCode] =
{ RETURN[DB.TypeForDomain[MsgSetDomain]] };
MsgSetType: DB.TypeSpec = [indirect[MsgSetTypeProc]];
ServerDomain: PUBLIC DB.Domain;
ServerTypeProc: PROC[] RETURNS[DB.TypeCode] =
{ RETURN[DB.TypeForDomain[ServerDomain]] };
ServerType: DB.TypeSpec = [indirect[ServerTypeProc]];
UnacceptedDomain: PUBLIC DB.Domain;
UnacceptedTypeProc: PROC[] RETURNS[DB.TypeCode] =
{ RETURN[DB.TypeForDomain[UnacceptedDomain]] };
UnacceptedType: DB.TypeSpec = [indirect[UnacceptedTypeProc]];
Global Relations - one each per database
Server entity Relation
sBasicInfo: PUBLIC DB.Relation;    -- One per Server
sBasicType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: ServerType],
[name: "messages", type: DB.Integer]
]];
MsgSet entity Relation
msBasicInfo: PUBLIC DB.Relation;    -- One per MsgSet
msBasicType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: MsgSetType],
[name: "count", type: DB.Integer],
[name: "version", type: DB.Integer],
[name: "printName", type: DB.String]
]];
Msg displaying Relation
mTextInfo: PUBLIC DB.Relation;   -- One per Msg
mTextType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: MsgType],
[name: "herald", type: DB.String, lengthHint: 60],
[name: "shortNameLen", type: DB.Integer],
[name: "entryStart", type: DB.Integer],
[name: "textOffset", type: DB.Integer],
[name: "textLen", type: DB.Integer],
[name: "formatLen", type: DB.Integer]
]];
Msg in MsgSet displayer relation
mDisplayInfo: PUBLIC DB.Relation;   -- One per Msg
mDisplayType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: MsgType],
[name: "tocEntry", type: DB.String, lengthHint: 70],
[name: "startOfSubject", type: DB.Integer],
[name: "hasBeenRead", type: DB.Boolean]
]];
Msg Date/Show relation
mInfo: PUBLIC DB.Relation;    -- One per Msg
mInfoType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: MsgType],
[name: "date", type: DB.Time],
[name: "show", type: UnacceptedType]
]];
Category/Date Relation
cdRelation: PUBLIC DB.Relation;    -- One per Msg / MsgSet pair
cdRelationType: DB.FieldSpec =
DB.L2FS[LIST[
[name: "of", type: MsgType],
[name: "msgSet", type: MsgSetType],
[name: "date", type: DB.Time]
]];
cdIndex: PUBLIC DB.Index;
cdIndexFieldSequence: DB.FieldSequence =
DB.L2F[LIST[WalnutSchema.cdMsgSet, WalnutSchema.cdDate]];
schemaDateField: DB.FieldSpec = DB.L2FS[LIST[[name: "schemaDate", type: DB.Time]]];
gSchemaDateInfoName: ROPE = "gSchemaDateInfo";
Procedures
Initialize: PUBLIC PROC [segment: WalnutDefs.Segment] = {
This procedure initializes the database schema, and commits it to the database.
DO
BEGIN ENABLE DB.Error =>
IF code = ProtectionViolation THEN GOTO readOnly ELSE GOTO badSchema;
gSchemaDateInfo: DB.Relation =
DB.DeclareRelation[gSchemaDateInfoName, segment, schemaDateField];
schemaRelship: DB.Relship ← DB.FirstRelship[gSchemaDateInfo];
IF schemaRelship = NIL THEN
schemaRelship ← DB.CreateRelship[gSchemaDateInfo, DB.L2VS[LIST[DB.T2V[schemaVersionDate]]]]
ELSE {
date: BasicTime.GMT = DB.V2T[DB.GetF[schemaRelship, 0]];
IF date = schemaVersionDate THEN EXIT;
ERROR WalnutDefs.SchemaMismatch[TimesToRope[date, schemaVersionDate]] };
EXITS
badSchema =>
ERROR WalnutDefs.SchemaMismatch[
TimesToRope[BasicTime.nullGMT, schemaVersionDate]];
readOnly =>
ERROR WalnutDefs.Error[
$db, $readOnly, "You only have read permission for this database"];
END;
ENDLOOP;
-- Define the Global Relations
gRootInfo ← DB.DeclareRelation["RootInfo", segment, gRootInfoFields];
gLogInfo ← DB.DeclareRelation["LogInfo", segment, gLogInfoFields];
gParseLogInfo ← DB.DeclareRelation["ParseLogInfo", segment, gParseLogInfoFields];
gExpungeInfo ← DB.DeclareRelation["ExpungeInfo", segment, gExpungeLogInfoFields];
gNewMailInfo ← DB.DeclareRelation["NewMailInfo", segment, gNewMailInfoFields];
gReadArchiveInfo ←
DB.DeclareRelation["ReadArchiveInfo", segment, gReadArchiveInfoFields];
gVersionInfo ← DB.DeclareRelation["VersionInfo", segment, gVersionInfoFields];
-- Define the Global Domains
MsgDomain ← DB.DeclareDomain["Msg", segment];
MsgSetDomain ← DB.DeclareDomain["MsgSet", segment];
ServerDomain ← DB.DeclareDomain["Server", segment];
UnacceptedDomain ← DB.DeclareDomain["Unaccepted", segment];
sBasicInfo ← DB.DeclareProperty["sBasicInfo", segment, sBasicType];
msBasicInfo ← DB.DeclareProperty["msBasicInfo", segment, msBasicType];
mTextInfo ← DB.DeclareProperty["mTextInfo", segment, mTextType];
mDisplayInfo ← DB.DeclareProperty["mDisplayInfo", segment, mDisplayType];
mInfo ← DB.DeclareProperty["mInfo", segment, mInfoType];
cdRelation ← DB.DeclareRelation["cdRelation", segment, cdRelationType];
-- Define the indicies
cdIndex ← DB.DeclareIndex[cdRelation, cdIndexFieldSequence];
check for relships
BEGIN
gr: DB.Relship ← DB.FirstRelship[gRootInfo];
IF gr = NIL THEN {
init: DB.ValueSequence ← DB.L2VS[ LIST[
[time[BasicTime.nullGMT]], [rope[NIL]], [rope[NIL]] ] ];
[] ← DB.CreateRelship[gRootInfo, init];
init ← DB.L2VS[ LIST[
[integer[0]], [integer[0]], [integer[0]], [integer[0]],
[time[BasicTime.nullGMT]] ] ];
[] ← DB.CreateRelship[gLogInfo, init];
init ← DB.L2VS[ LIST[ [boolean[FALSE]], [integer[0]] ] ];
[] ← DB.CreateRelship[gParseLogInfo, init];
init ← DB.L2VS[ LIST[
[integer[0]], [integer[0]], [integer[0]], [integer[0]],
[time[BasicTime.nullGMT]]
] ];
[] ← DB.CreateRelship[gExpungeInfo, init];
init ← DB.L2VS[LIST[
[integer[0]], [integer[0]], [integer[0]],
[boolean[FALSE]], [time[BasicTime.nullGMT]]
] ];
[] ← DB.CreateRelship[gNewMailInfo, init];
init ← DB.L2VS[ LIST[ [integer[0]], [integer[0]] ] ];
[] ← DB.CreateRelship[gReadArchiveInfo, init];
MsgCount: 0, MsgSetCount: 2, MsgSetsVersion: 1
init ← DB.L2VS[ LIST[ [integer[0]], [integer[2]], [integer[1]] ] ];
[] ← DB.CreateRelship[gVersionInfo, init];
};
END;
-- Commit what we've done
WalnutRoot.CommitAndContinue[];
};
SetSchemaVersion: PUBLIC PROC[segment: WalnutDefs.Segment] = {
this doesn't commit, so it can be used by NewWalnutUser
gSchemaDateInfo: DB.Relation =
DB.DeclareRelation[gSchemaDateInfoName, segment, schemaDateField];
schemaRelship: DB.Relship ← DB.FirstRelship[gSchemaDateInfo];
IF schemaRelship # NIL THEN
DB.SetF[schemaRelship, 0, DB.T2V[schemaVersionDate]]
ELSE schemaRelship ←
DB.CreateRelship[gSchemaDateInfo, DB.L2VS[LIST[DB.T2V[schemaVersionDate]]]];
WalnutRoot.CommitAndContinue[];
};
TimesToRope: PROC[is, shouldBe: BasicTime.GMT] RETURNS[ROPE] = {
isR, shouldR: ROPE;
isR ← IO.PutFR[NIL, IO.time[is ! BasicTime.OutOfRange => isR ← "OutOfRange"]];
shouldR ← IO.PutFR[NIL, IO.time[shouldBe ! BasicTime.OutOfRange =>
shouldR ← "OutOfRange"]];
RETURN[Rope.Cat["\nSchema is of: ", isR, " but should be of: ", shouldR]];
};
END.