-- File: NutDumpImpl.mesa
-- Contents: Program to do ascii database output.
-- Status: Runs in Cedar as subordinate of Squirrel.
-- Created by: Rick Cattell, March 1980; stolen from DBDump created September 1980
-- Last Edited by:
-- Cattell on: June 3, 1983 2:26 pm
-- Maxwell on: June 4, 1982 12:10 pm
-- Willie-Sue on: February 22, 1983 3:47 pm
-- Donahue on: April 5, 1983 10:13 am
-- Output formats:
-- SegmentName [other info] on the first line
-- /Domain|name|nametype| ...for each domain
-- /Relation|name| ...for each relation
-- /Attribute|name|relation|type|cardinality|length|link| ...for each attribute
-- /Index|relation|attribute|...|| .. for each index
-- /domain|name-elt1|name-elt2|...| ...for each entity
-- |relation|attr1:val1|attr2:val2|...| ...for each relship
-- In entity-centric mode, prints entities and relships that ref them in first attribute together.
DIRECTORY
Atom USING [MakeAtom],
BasicTime,
DBEnvironment USING [InternalError],
DB,
FS USING[StreamOpen],
IO,
NutDump,
NutOps,
NutViewer,
Rope,
SquirrelTool,
ViewerClasses;
NutDumpImpl: CEDAR PROGRAM
IMPORTS
Atom, DBEnvironment, DB, FS, IO, NutOps, NutViewer, Rope, SquirrelTool, BasicTime
EXPORTS
NutDump -- DumpToFile -- =
BEGIN OPEN DB, IO, NutViewer;
inf: CARDINAL = 177777B;
IllegalEntity: SIGNAL = CODE;
IllegalFormat: SIGNAL = CODE;
squirrel: ViewerClasses.Viewer = SquirrelTool.squirrel;
start: BasicTime.GMT;
elapsedTime: INT;
entityCentricFlag: BOOL;
word: PROC [u: UNSPECIFIED] RETURNS [IO.Value] =
-- temporary kluge for output of UNSPECIFIED to IO
INLINE {RETURN[[integer[LOOPHOLE[u, INTEGER]]]]};
-- Main procedure, exported to NutDump
DumpToFile: PUBLIC PROC[segment: ROPE, fileName: ROPE, dl: LIST OF DB.Domain ← NIL,
rl: LIST OF DB.Relation ← NIL, complement: BOOL ← FALSE, entityCentric: BOOL ← FALSE] =
TRUSTED BEGIN
{ENABLE ABORTED => GO TO SqueakyClean;
file: IO.STREAM;
seg: Segment;
found: BOOLEAN ← FALSE;
start ← BasicTime.Now[];
entityCentricFlag← entityCentric;
IF segment=NIL OR segment.Length[] = 0 THEN
{ Message[squirrel, "Must specify a segment to dump"]; RETURN};
IF fileName = NIL THEN fileName ← segment.Concat[".dump"];
file ← OpenFile[fileName];
seg← Atom.MakeAtom[segment];
FOR sl: LIST OF Segment ← DB.GetSegments[], sl.rest UNTIL sl = NIL DO
IF sl.first = seg THEN { found ← TRUE; EXIT } ENDLOOP;
IF NOT found THEN { Message[squirrel, segment, " not open; aborting dump"]; RETURN };
Message[squirrel, "Dumping to ", fileName, ": "];
MessageRope[squirrel, "Data schema ..."];
IF complement THEN {
dl ← Complement[dl, EntitySetToList[DomainSubset[d: DomainDomain, searchSegment: seg]]];
rl ← Complement[rl, EntitySetToList[DomainSubset[d: RelationDomain, searchSegment: seg]]]};
file.Put[rope[segment], rope[" ["], time[]];
file.Put[rope["]\n"]];
WriteSchema[file, dl, rl];
MessageRope[squirrel, "Domains: "];
-- Output Domain contents
FOR list: LIST OF Domain ← dl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
MessageRope[squirrel, GetName[list.first]]; MessageRope[squirrel, "... "];
WriteDomain[file, list.first];
ENDLOOP;
IF entityCentric THEN {
MessageRope[squirrel, "Domain references: "];
FOR list: LIST OF Domain ← dl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
MessageRope[squirrel, GetName[list.first]]; MessageRope[squirrel, "... "];
WriteDomain[file, list.first, TRUE];
ENDLOOP;
MessageRope[squirrel, "Other "];
-- Output Relation contents
};
MessageRope[squirrel, "Relations: "];
-- Output Relation contents
FOR list: LIST OF Relation ← rl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
IF entityCentric AND FirstAttributeIsDomain[list.first] THEN LOOP;
MessageRope[squirrel, GetName[list.first]]; MessageRope[squirrel, "... "];
WriteRelation[file, list.first];
ENDLOOP;
CloseFile[file];
elapsedTime ← BasicTime.Period[ from: start, to: BasicTime.Now[] ];
Message[squirrel, PutFR["Dump completed: %g elapsed seconds.\n", int[elapsedTime]] ];
EXITS SqueakyClean => {}};
END;
FirstAttributeIsDomain: PROCEDURE[r: Relation]
RETURNS[BOOL] =
{RETURN[NutOps.EntityValued[NutOps.FirstAttributeOf[r]]]};
Complement: PROCEDURE[ignore: LIST OF Entity, all: LIST OF Entity]
RETURNS[complement: LIST OF Entity] =
BEGIN
found: BOOLEAN;
complementEnd: LIST OF Entity← NIL;
IF ignore = NIL THEN RETURN[all];
FOR listA: LIST OF Entity ← all, listA.rest WHILE listA # NIL DO
found ← FALSE;
FOR listI: LIST OF Entity ← ignore, listI.rest WHILE listI # NIL DO
IF Eq[listI.first, listA.first] THEN {found ← TRUE; EXIT};
ENDLOOP;
IF ~found THEN
-- Add to end of complement list (if NIL, create first element)
IF complement=NIL THEN
complement← complementEnd← LIST[listA.first]
ELSE
complementEnd← complementEnd.rest ← LIST[listA.first];
ENDLOOP;
END;
OpenFile: PUBLIC PROC[fileName: ROPE] RETURNS[file: IO.STREAM] =
TRUSTED BEGIN
IF fileName=NIL THEN {Message[squirrel, "Illegal file name for dump"]; RETURN};
file ← FS.StreamOpen[fileName: fileName, accessOptions: $create]
END;
CloseFile: PUBLIC PROC[fileStream: STREAM] = {fileStream.Close[]};
-- The output routines.
WriteSchema: PUBLIC PROC[s: IO.STREAM, dl: LIST OF DB.Domain, rl: LIST OF DB.Relation] =
BEGIN
subtype: Relship;
subtypeList: RelshipSet;
-- Output Domains
FOR list: LIST OF Domain ← dl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
WriteSystemEntity[s, list.first];
ENDLOOP;
-- Output SubTypes
FOR list: LIST OF Domain ← dl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
subtypeList ← RelationSubset[dSubType, LIST[[dSubTypeOf, list.first]]];
UNTIL Null[subtype← NextRelship[subtypeList]] AND NOT SquirrelTool.stopped DO
WriteSystemRelship[s, subtype]
ENDLOOP;
ReleaseRelshipSet[subtypeList];
ENDLOOP;
-- Output Relations
FOR list: LIST OF Relation ← rl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
WriteSystemEntity[s, list.first];
ENDLOOP;
-- Output Attributes
FOR list: LIST OF Relation ← rl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
FOR aL: LIST OF Attribute← VL2EL[GetPList[list.first, aRelationOf]],
aL.rest UNTIL aL=NIL DO
WriteSystemEntity[s, aL.first]
ENDLOOP;
ENDLOOP;
-- Output Indexes
FOR list: LIST OF Relation ← rl, list.rest WHILE list # NIL AND NOT SquirrelTool.stopped DO
r: Relation← list.first;
FOR iL: LIST OF Index ← GetIndicesFor[r], iL.rest UNTIL iL = NIL OR SquirrelTool.stopped DO
WriteSystemEntity[s, iL.first, NameOf[r]]
ENDLOOP
ENDLOOP;
END;
WriteSystemEntity: PUBLIC PROC [s: IO.STREAM, e: Entity, also: ROPE← NIL] =
-- Will print a domain, relation, attribute, or index and any
-- associated properties that are needed to recreate it.
BEGIN type: Domain← DomainOf[e];
IF SquirrelTool.stopped THEN RETURN;
SELECT type FROM
DomainDomain =>
s.Put[rope["/Domain|"], rope[GetName[e]], char['|]];
RelationDomain => s.Put[
rope["/Relation|"], rope[GetName[e]], char['|] ];
AttributeDomain => {
s.Put[rope["/Attribute|"], rope[GetName[V2E[GetP[e, aRelationIs]]]], char['|]];
s.Put[rope[GetName[e]], char['|]];
s.Put[rope[GetName[V2E[GetP[e, aTypeIs]]]], char['|]];
s.Put[word[V2U[GetP[e, DB.aUniquenessIs]]], char['|]];
s.Put[int[V2I[GetP[e, DB.aLengthIs]]], char['|]];
s.Put[word[V2U[GetP[e, DB.aLinkIs]]], char['|]] };
IndexDomain => {
-- First get all of the index factors for this index,
-- then the attribute associated with each index factor and print it
s.Put[rope["/Index|"], rope[also], rope["|"]];
FOR ifList: LIST OF DB.Value ← GetPList[e, ifIndexOf, ifIndexIs], ifList.rest
UNTIL ifList = NIL OR SquirrelTool.stopped DO
s.Put[ rope[NameOf[V2E[GetP[V2E[ifList.first], ifAttributeIs]]]], rope["|"] ]
ENDLOOP;
s.Put[ rope["|"] ] };
ENDCASE;
s.Put[char[CR]];
END;
WriteSystemRelship: PUBLIC PROC [s: IO.STREAM, r: Relship] =
-- Prints a subtype relship.
BEGIN
IF SquirrelTool.stopped THEN RETURN;
s.Put[rope["|SubType|"]];
s.Put[rope["of:"], rope[GetFS[r, dSubTypeOf]], char['|]];
s.Put[rope["is:"], rope[GetFS[r, dSubTypeIs]], char['|]];
s.Put[char[CR]];
END;
WriteDomain: PUBLIC PROC[s: IO.STREAM, d: Domain, refs: BOOL← FALSE] =
-- Prints entities unless refs=TRUE, in which case prints relships reffing.
BEGIN
entity: Entity;
entityList: EntitySet← DomainSubset[d: d, searchSubDomains: FALSE];
UNTIL Null[entity← NextEntity[entityList]] OR SquirrelTool.stopped DO
IF refs THEN WriteRelatedRelships[s, entity] ELSE WriteEntity[s, entity] ENDLOOP;
ReleaseEntitySet[entityList];
END;
WriteEntity: PUBLIC PROC[s: IO.STREAM, e: Entity] =
-- Prints an entity in ascii dump form: /domain\name\
TRUSTED BEGIN ENABLE DBEnvironment.InternalError => GOTO Error;
d: Domain← DomainOf[e];
IF SquirrelTool.stopped THEN RETURN;
s.Put[char['/], rope[GetName[d]], char['|]];
s.Put[rope[GetName[e]], char['|], char[CR]];
EXITS Error =>
{Message[squirrel, "Ouch! Internal error on entity ", GetName[e]]};
END;
WriteRelatedRelships: PUBLIC PROC[fh: IO.STREAM, e: Entity] =
-- Prints relships that reference e in their first attribute.
BEGIN
t: Relship;
r: Relation;
rs: RelshipSet;
al: AttributeList;
al← GetAllRefAttributes[e];
FOR alT: AttributeList← al, alT.rest UNTIL alT=NIL DO
r← V2E[GetP[alT.first, aRelationIs]];
IF Eq[alT.first, NutOps.FirstAttributeOf[r]] THEN
BEGIN
rs← RelationSubset[r, LIST[[alT.first, e]]];
UNTIL Null[t← NextRelship[rs]] DO
WriteRelship[fh, t] ENDLOOP;
ReleaseRelshipSet[rs];
END;
ENDLOOP;
END;
WriteRelation: PUBLIC PROC[s: IO.STREAM, r: Relation] =
BEGIN
relship: Relship;
relshipList: RelshipSet← RelationSubset[r];
UNTIL Null[relship← NextRelship[relshipList]] OR SquirrelTool.stopped DO
WriteRelship[s, relship] ENDLOOP;
ReleaseRelshipSet[relshipList];
END;
WriteRelship: PUBLIC PROC[s: IO.STREAM, r: Relship] =
-- Prints a relship in ascii dump form: \relation\a1:v1\...\aN:vN\
TRUSTED BEGIN ENABLE DBEnvironment.InternalError => GOTO Error;
ts: Relation← RelationOf[r];
IF SquirrelTool.stopped THEN RETURN;
s.Put[char['|], rope[GetName[ts]], char['|]];
FOR aL: LIST OF Attribute← VL2EL[GetPList[ts, aRelationOf]], aL.rest UNTIL aL=NIL DO
s.Put[rope[GetName[aL.first]], char[':]];
s.Put[rope[GetFS[r, aL.first]], char['|]];
ENDLOOP;
s.Put[char[CR]];
EXITS Error =>
{Message[squirrel, "Ouch! Internal error on relship"]};
END;
GetIndicesFor: PROC [r: Relation] RETURNS [LIST OF Index] =
-- Returns the list of indices on r. Must first find attributes of r, then find any index
-- factors involving those attributes, then find the indices to which the index factors belong,
-- removing duplicates (indices with more than one index factor will appear more than once).
BEGIN il: LIST OF Index ← NIL;
FOR al: LIST OF Attribute ← VL2EL[GetPList[r, aRelationOf]], al.rest UNTIL al=NIL DO
if: IndexFactor ← V2E[GetP[al.first, ifAttributeOf]];
IF if#NIL THEN il ← AppendIfNew[V2E[GetP[if, ifIndexIs]], il];
ENDLOOP;
RETURN[il]
END;
AppendIfNew: PROC[e: Entity, el: LIST OF Entity] RETURNS [LIST OF Entity] =
-- Add entity e to list el if it is not already in the list.
BEGIN elT: LIST OF Entity;
FOR elT← el, elT.rest UNTIL elT=NIL DO IF Eq[elT.first, e] THEN RETURN[el] ENDLOOP;
RETURN[CONS[e, el]];
END;
END.
Change log since October 1982:
By Cattell October 11, 1982 10:54 pm: Changed Complement procedure so that it keeps the list in the same order as the input, but using a complementEnd variable. Added timing of dump.
Willie-Sue December 13, 1982: aFooProp => aFooIs, for new system properties.
Willie-Sue January 11, 1983 3:32 pm: new output format for segments
Cattell April 6, 1983 10:35 am: fix comments at top.
Cattell November 18, 1983 4:27 pm: convert to new format allowing "\"s in relship fields.