-- File: NutLoadImpl.mesa -- Contents: program to do ascii database input to segment. -- Created by Rick Cattell on: August 25, 1980 -- Last edited by -- Cattell on: June 6, 1983 1:24 pm -- Maxwell on: June 4, 1982 12:09 pm -- Willie-Sue on: February 22, 1983 3:57 pm -- Donahue on: March 22, 1983 8:46 am DIRECTORY Atom, DB, FileIO, Inline, IO, NutDump, NutOps, NutViewer, Process, Rope, SquirrelTool, System; NutLoadImpl: CEDAR PROGRAM IMPORTS Atom, DB, FileIO, Inline, IO, NutOps, NutViewer, Rope, System, SquirrelTool EXPORTS NutDump -- LoadFromFile -- = BEGIN OPEN DB, IO; ControlZ: CHARACTER = 032C; startFlag: BOOLEAN_ TRUE; entityCount, relshipCount, lineCount: INT; MissingField: SIGNAL = CODE; CommitLimit: INT= 1024; -- commits database every time this many lines read autoCommitted: BOOL_ FALSE; -- set if more than CommitLimit tuples read autoCreate: BOOL_ TRUE; -- whether to automatically create entities ref'd & when don't exist defaultSegment: Segment_ NIL; -- Main procedure, exported to SquirrelOps: LoadFromFile: PUBLIC PROC[dumpFile: ROPE _ NIL, DBFile: ROPE _ NIL] = -- Loads whatever is in the dumpFile file; uses same dump format as DumpToFile. TRUSTED BEGIN ENABLE Process.Aborted => {NutViewer.Message[NIL, "Aborting input!\n"]; CONTINUE}; elapsedTime: System.GreenwichMeanTime_ System.GetGreenwichMeanTime[]; BracketProc: IO.BreakProc = CHECKED { RETURN[ IF char='] THEN CharClass[break] ELSE CharClass[other] ] }; timeRope, segmentNameInFile, defaultSegmentName: ROPE; lineCount_ entityCount _ relshipCount_ 0; defaultSegment _ NutOps.AtomFromSegment[DBFile]; defaultSegmentName_ Atom.GetPName[defaultSegment]; IF dumpFile=NIL OR dumpFile.Length[]=0 THEN dumpFile _ "DB.dump"; in_ FileIO.Open[dumpFile, read]; IF in=NIL THEN {NutViewer.Message[NIL, "Can't open ", dumpFile]; RETURN}; segmentNameInFile _ in.GetToken[]; [] _ in.GetToken[]; -- throw away the leading '[ timeRope _ in.GetToken[BracketProc]; [] _ in.GetToken[]; -- throw away the trailing '] [] _ in.GetChar[]; -- and the CR following it IF NOT Rope.Equal[segmentNameInFile, Atom.GetPName[defaultSegment]] THEN { NutViewer.Message[NIL, "You don't want to do this; file was dump of ", segmentNameInFile, " segment; you are loading ", defaultSegmentName]; RETURN }; NutViewer.Message[NIL, Rope.Cat["Reading segment ", defaultSegmentName, " from "], dumpFile, "...\n"]; NutOps.SetUpSegment[ DBFile, defaultSegment ! DB.Error => TRUSTED { IF code=MismatchedExistingSegment THEN GO TO BadSegment} ]; InputMR[]; elapsedTime_ LOOPHOLE[System.GetGreenwichMeanTime[] - elapsedTime]; NutViewer.Message[NIL, PutFR["Load complete: %g entities and %g tuples, %g elapsed seconds.\nSave or Reset updates.\n", int[entityCount], int[relshipCount], int[elapsedTime]] ]; EXITS BadSegment => NutViewer.Message[NIL, "Existing file name or segment number doesn't match! Aborting..."]; END; Declared: PROC[ seg: Segment ] RETURNS[ is: BOOLEAN ] = { FOR sl: LIST OF Segment _ GetSegments[], sl.rest UNTIL sl = NIL DO IF sl.first = seg THEN RETURN[ TRUE ] ENDLOOP; RETURN[ FALSE ] }; -- Global variables in: IO.Handle; InputMR: PROC = TRUSTED BEGIN ENABLE BEGIN EndOfStream => {NutViewer.MessageRope[NIL, "Unexpected EOF! Aborting input...\n"]; GOTO Return}; IO.Error => {IllegalFormat["Unrecoverable error! Aborting input..."]; GOTO Return} END; UNTIL in.EndOf[] OR SquirrelTool.stopped DO BEGIN ENABLE MissingField => {IllegalFormat["missing field in dictionary tuple"]; LOOP}; SELECT in.GetChar[] FROM '/ => BEGIN d: ROPE_ ReadString[FALSE]; IF d.Length[]=0 THEN {IllegalFormat["missing domain name"]; LOOP}; SELECT TRUE FROM -- check for system entity type d.Equal["Domain"] => BEGIN name: ROPE = ReadString[]; []_ DeclareDomain[name, defaultSegment, NewOrOld, EstimateRefs[name]]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; END; d.Equal["Relation"] => BEGIN name: ROPE = ReadString[]; []_ DeclareRelation[name: name, segment: defaultSegment, version: NewOrOld]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; END; d.Equal["Attribute"] => BEGIN relationName: ROPE = ReadString[]; name, typeName: ROPE; type: DataType; unique: Uniqueness; length: INT; link: LinkType; relation: Relation = FetchEntity[RelationDomain, relationName, defaultSegment]; IF relation = NIL THEN {IllegalFormat[relationName, " not a relation"]; LOOP}; name _ ReadString[]; typeName_ ReadString[]; type_ LookupDataType[typeName]; IF type = NIL THEN {IllegalFormat[typeName, " not a type"]; LOOP}; unique_ ReadEnum[]; length_ ReadNum[]; link _ ReadEnum[]; []_ DeclareAttribute[relation, name, type, unique, length, link]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; END; d.Equal["Index"] => BEGIN rName: ROPE = ReadString[]; rel: Relation = DeclareRelation[rName, defaultSegment]; attrList: LIST OF Attribute; FOR nextName: ROPE _ ReadString[FALSE], ReadString[FALSE] UNTIL Rope.Equal[nextName, ""] DO attrList _ CONS[ DeclareAttribute[rel, nextName], attrList ] ENDLOOP; IF attrList # NIL THEN [] _ DeclareIndex[ rel, attrList, Version[NewOrOld] ]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; END; ENDCASE => -- just a normal entity type ReadEntity[d]; NutViewer.MessageRope[NIL, "."]; END; '\\ => BEGIN r: ROPE_ ReadString[FALSE]; IF r.Length[]=0 THEN {IllegalFormat["missing relation name"]; LOOP}; IF r.Equal["SubType"] THEN BEGIN ENABLE DB.Error => TRUSTED {IF code=NotFound THEN { IllegalFormat["bad subtype: domain does not exist"]; LOOP } }; ofS: ROPE_ ReadName[]; of: ROPE_ ReadString[]; isS: ROPE_ ReadName[]; is: ROPE_ ReadString[]; IF NOT (ofS.Equal["of"] AND isS.Equal["is"]) THEN {IllegalFormat["illegal subtype syntax"]; LOOP}; DeclareSubType[ of: DeclareDomain[name: of, segment: defaultSegment, version: OldOnly], is: DeclareDomain[name: is, segment: defaultSegment, version: OldOnly]]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; END ELSE ReadRelship[r]; NutViewer.MessageRope[NIL, "."]; END; ENDCASE => {NutViewer.MessageRope[NIL, "-"]; SkipThruCR[]}; -- treat as comment END ENDLOOP -- of UNTIL in.EndOf[] --; IF autoCommitted THEN MarkTransaction[TransactionOf[defaultSegment]]; EXITS Return => NULL; END; ReadEntity: PROC [dName: ROPE] = BEGIN ENABLE MissingField => {IllegalFormat["missing name field"]; GOTO Return}; eName: ROPE; d: Domain_ DeclareDomain[dName, defaultSegment, OldOnly ! Error => {IllegalFormat[dName, " not a domain"]; GOTO Return}]; e: Entity; eName_ ReadString[]; e_ DeclareEntity[d, eName]; IF in.GetChar[]#CR THEN IllegalFormat["Missing CR"]; NextLine[Entity]; EXITS Return => NULL END; ReadRelship: PROC [rName: ROPE] = TRUSTED BEGIN ENABLE MissingField => {IllegalFormat[rName, " tuple has missing field"]; GOTO Return}; r: Relation = DeclareRelation[rName, defaultSegment, OldOnly ]; rel: Relship; val, fieldName: ROPE; field: Attribute; IF r = NIL THEN {IllegalFormat[rName, " not a relation"]; GOTO Return}; rel _ CreateRelship[r]; UNTIL (fieldName _ ReadName[])=NIL DO BEGIN field_ DeclareAttribute[r: r, name: fieldName, version: OldOnly]; IF field=NIL THEN {IllegalFormat[fieldName, " not an attribute of this relation"]; GOTO Return}; val_ ReadString[FALSE]; SetFS[rel, field, val ! DB.Error => TRUSTED { SELECT code FROM NotFound => GOTO MissingEntity; MustSetKeyAttributeFirst => {IllegalFormat[fieldName, " attribute out of order"]; GOTO Return}; MultipleMatch, NonUniqueKeyValue => {IllegalFormat[val, " value is key stored more than once"]; GOTO Return}; ENDCASE => NULL }]; EXITS MissingEntity => IF autoCreate THEN BEGIN dom: Domain_ V2E[GetP[field, aTypeIs]]; NutViewer.Message[NIL, "Automatically creating ref'd entity ", GetName[dom], ": ", val]; IF Eq[dom, AnyDomainType] THEN -- must dissect val into REAL domain and val BEGIN -- it's of form ": ", set dom and val accordingly pos: INT_ val.Find[":"]; IF pos=-1 THEN {IllegalFormat["Missing domain in AnyDomainType field"]; GOTO Return}; dom _ DeclareDomain[val.Substr[0, pos], defaultSegment, OldOnly]; IF dom = NIL THEN {IllegalFormat["No such domain"]; GOTO Return}; val_ val.Substr[pos+2]; END; SetF[rel, field, CreateEntity[dom, val]]; END ELSE {IllegalFormat[val, " does not exist"]; GOTO Return}; END ENDLOOP; NextLine[Relship]; EXITS Return => NULL END; -- Input support routines NextLine: PROC [kind: {Entity, Relship}] = TRUSTED BEGIN ePos: INT; IF kind=Entity THEN entityCount_ entityCount+1 ELSE relshipCount_ relshipCount+1; IF (lineCount_ lineCount+1) MOD CommitLimit # 0 THEN RETURN; autoCommitted_ TRUE; ePos_ in.GetIndex[]; NutViewer.MessageRope[NIL, PutFR["\nAutomatic commit at %g: ", int[ePos]]]; DB.MarkTransaction[TransactionOf[defaultSegment]]; END; IllegalFormat: PROC[msg, arg: ROPE_ NIL] = TRUSTED BEGIN ePos: INT_ in.GetIndex[]; NutViewer.MessageRope[NIL, "\nInput error at "]; NutViewer.MessageRope[NIL, PutFR[,int[ePos]]]; IF msg#NIL THEN {NutViewer.MessageRope[NIL, ": "]; NutViewer.MessageRope[NIL, msg]}; IF arg#NIL THEN NutViewer.MessageRope[NIL, arg]; NutViewer.Message[NIL, ]; SkipThruCR[]; END; SkipThruCR: SAFE PROC = CHECKED BEGIN c: CHARACTER; WHILE (c_ in.GetChar[]) # CR DO ENDLOOP; END; ReadName: PROC RETURNS[ROPE] = -- Terminates on reading a ":" or a CR; returns NIL in latter case. BEGIN lastBreak: CHAR; skipping: BOOL _ FALSE; s: ROPE_ in.GetToken[NameBreak]; NameBreak: BreakProc = CHECKED { lastBreak _ char; IF skipping THEN RETURN[IF char = CR THEN CharClass[break] ELSE CharClass[other]]; IF char=ControlZ THEN {skipping _ TRUE; RETURN[CharClass[other]]}; IF char='\\ OR char=CR OR char=': THEN RETURN[CharClass[break]]; RETURN[CharClass[other]] }; IF Rope.Equal[s, "\\"] OR Rope.Equal[s, "\n"] THEN s_ "" ELSE [] _ in.GetChar[]; -- throw away the break character IF s.Length[]=0 THEN IF lastBreak=': THEN ERROR MissingField ELSE RETURN[NIL] ELSE RETURN[s] END; ReadString: PROC[nonNull: BOOLEAN_ TRUE] RETURNS[ROPE] = -- Terminates on reading a "\"; may return a null string if find immediately. -- Null string generates error if nonNull=TRUE. BEGIN s: ROPE _ in.GetToken[NameBreak]; NameBreak: BreakProc = CHECKED { IF char='\\ THEN RETURN[CharClass[break]] ELSE RETURN[CharClass[other]] }; IF Rope.Equal[s, "\\"] THEN s_ "" ELSE [] _ in.GetChar[]; -- if didn't hit '\\ immediately, throw it away IF s.Length[]=0 AND nonNull THEN ERROR MissingField ELSE RETURN[s] END; ReadEnum: PROC RETURNS[UNSPECIFIED] = -- Read a num, return as UNSPECIFIED so can store in enum type -- currently doesn't check that terminates with '\\ or that present at all BEGIN RETURN[Inline.LowHalf[ReadNum[]]] END; ReadNum: PROC RETURNS[INT] = -- currently doesn't check that terminates with '\\ or that present at all BEGIN SlashBreak: BreakProc = CHECKED {IF char='\\ THEN RETURN[ CharClass[break] ] ELSE RETURN[ CharClass[other] ] }; is: ROPE _ in.GetToken[SlashBreak]; [] _ in.GetChar[]; RETURN[GetInt[RIS[is]]]; END; ReadBool: PROC RETURNS[BOOL] = BEGIN SlashBreak: BreakProc = CHECKED {IF char='\\ THEN RETURN[ CharClass[break] ] ELSE RETURN[ CharClass[other] ] }; is: ROPE_ in.GetToken[SlashBreak]; [] _ in.GetChar[]; RETURN[GetBool[RIS[is]]]; END; LookupDataType: PROC [name: ROPE] RETURNS [DataType] = BEGIN SELECT TRUE FROM name.Equal["IntType"] => RETURN[IntType]; name.Equal["BoolType"] => RETURN[BoolType]; name.Equal["RecordType"] => RETURN[RecordType]; name.Equal["StringType"] => RETURN[StringType]; name.Equal["TimeType"] => RETURN[TimeType]; name.Equal["AnyDomainType"] => RETURN[AnyDomainType]; ENDCASE => RETURN[DeclareDomain[name, defaultSegment, OldOnly]]; END; EstimateRefs: PROC[domain: ROPE] RETURNS [CARDINAL] = -- What a hack! BEGIN RETURN[IF Rope.Equal[domain, "Person"] OR Rope.Equal[domain, "Msg"] THEN 10 ELSE 5] END; END. Change Log: March 25, 1982 5:20 pm by Cattell: converted from DBLoad. October 13, 1982 12:14 pm by Cattell: autoCreate, autoCommit enabled. Added timing of load. December 1, 1982 6:56 pm by Cattell: ReadRelship now works properly with autoCreate=TRUE when multiple or AnyDomainType undefined entity fields. Willie-Sue December 13, 1982: aFooProp => aFooIs, for new system properties Cattell April 19, 1983 1:15 pm: put back in autoCommit someone took out; it is necessary for large file DBLoads! ĘU˜Jš’Īc—œ$œ%œSœĪk œ†žœžœžœPžœ œžœžœžœžœ ž œžœžœ)žœžœžœ]žœžœ,œ žœžœEœžœ,œĪn œžœžœ žœžœ žœžœPœžœžœžœBžœZžœžœžœžœ žœžœJžœ˜žœ žœžœžœ<žœžœžœ3žœ>œ=œœžœžœ>žœĄžœ–žœéžœ žœ^žœŸœžœžœžœžœžœžœ"žœžœžœžœžœžœžœžœžœžœœžœ Ÿœžœžœžœžœžœ_žœžœKžœ žœžœ žœžœžœžœMžœžœžœžœžœ žœžœžœ(žœžœžœžœ œ%žœžœjžœžœžœ*žœ)žœžœpžœžœžœ'žœ*žœžœ*žœIžœ}žœ žœžœ2žœvžœžœžœ*žœ­žœžœžœ'žœ&žœžœežœžœžœ žœžœžœ žœžœžœ9žœ žœ žœžœAžœžœžœ'žœ žœœCžœžœžœ žœžœžœ*žœžœžœžœ žœžœžœžœžœMžœžœžœžœžœžœžœžœžœ4žœÄžœžœžœ%žœžœCžœžœ=œžœžœœLžœ žœžœŸ œžœ žœžœžœ;žœžœužœOžœžœžœ4žœ žœžœŸ œžœ žœžœžœžœDžœožœžœžœžœ+žœ&žœžœžœžœ¤žœžœžœ žœ žœžœžœsžœ|žœžœžœ žœžœ žœ žœ’žœžœ-œ žœ@œžœžœžœFžœ`žœžœžœ#žœ6žœ<žœžœ1žœžœžœžœ žœžœœŸœžœžœžœžœžœ žœžœ!žœžœžœžœžœžžœŸ œžœ žœžœžœžœžœwžœžœžœHžœžœžœPžœŸ œžœžœžœžœž œžœžœžœžœžœŸœžœžœžœDœžœžœžœžœžœ4žœžœ žœžœžœžœžœ Īrœžœžœžœ žœžœžœ žœžœžœ žœžœ  œžœ  œžœžœžœ žœ!œžœžœžœžœžœžœžœžœžœžœžœŸ œžœ žœžœžœžœNœ0œžœžœ(  œžœžœ žœžœ  œžœžœžœžœ žœ0œžœžœ žœžœžœžœžœŸœžœžœž œ?œKœžœžœžœŸœžœžœžœKœžœžœžœ žœžœžœžœžœ3žœžœ žœŸœžœžœžœžœžœžœ žœžœžœžœžœ2žœ žœ žœŸœžœžœžœžœžœžœžœžœ)žœ,žœ.žœ,žœ/žœžœžœ2žœŸ œžœ žœžœžœœžœžœžœžœžœžœžœžœũžœ÷˜‡i—…—4Š;å