-- File: DBImpl.mesa
-- Purpose: Monitored interface to DB, to keep only one client in database system at a time.
-- Contains one ENTRY per DB procedure (except those that need not be monitored, like Eq).
-- The procs simply call the internal procs in the DBModel*Impls. DBImpl also does all the
-- top-level statistics-taking (using DBStats) because it's easier to do here, and has some procs
-- that are only temporarily in the database system.
-- Created by Haugeland and Cattell, April 1982
-- Last edited by:
-- Rick Cattell on November 2, 1983 10:13 am
-- Willie-Sue, February 3, 1983 10:50 am


DIRECTORY
Atom, Rope, DB, DBModel, DBModelPrivate, DBStats, FS, IO;

DBImpl: CEDAR MONITOR
IMPORTS Atom, DB, DBModel, DBModelPrivate, DBStats, FS, IO, Rope
EXPORTS DB =

BEGIN OPEN DB;

ROPE: TYPE = Rope.ROPE;



-- *** Part 1: Global top-level operations [DBModelGlobalImpl]

Initialize: PUBLIC ENTRY PROC[
nCachePages: NAT← 512, nFreeTuples: NAT← 32,
cacheFileName: ROPE← NIL, augments: BOOL← FALSE] = TRUSTED
{ ENABLE UNWIND => NULL;
DBStats.Initialize[];
DBModel.QInitialize[nCachePages, nFreeTuples, cacheFileName, augments];
RETURN};

OpenTransaction: PUBLIC ENTRY PROC[
segment: Segment← NIL,
userName, password: ROPE← NIL,
useTrans: Transaction← NIL,
noLog: BOOL← FALSE] = TRUSTED
{ ENABLE UNWIND => NULL; DBStats.Starting[OpenToClose];
DBModel.QOpenTransaction[segment, useTrans, noLog]};

MarkTransaction: PUBLIC ENTRY PROC[trans: Transaction] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QMarkTransaction[trans]};

AbortTransaction: PUBLIC ENTRY PROC[trans: Transaction] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QAbortTransaction[trans]; PrintStats["Aborting"]};

CloseTransaction: PUBLIC ENTRY PROC[trans: Transaction] = TRUSTED
{ ENABLE UNWIND => NULL;
DBModel.QCloseTransaction[trans];
DBStats.Stopping[OpenToClose];
PrintStats["Closing"]};

DeclareSegment: PUBLIC ENTRY PROC[
filePath: ROPE, segment: Segment← NIL, number: NAT← 0, readonly: BOOL← FALSE,
createIfNotFound: BOOL← TRUE, nBytesInitial, nBytesPerExtent: INT← 32768] = TRUSTED
{ ENABLE UNWIND => NULL;
DBModel.QDeclareSegment[
filePath, segment, number, readonly, createIfNotFound, nBytesInitial, nBytesPerExtent]};

EraseSegment: PUBLIC ENTRY PROC[segment: Segment] = TRUSTED
{ ENABLE UNWIND => NULL;
DBModel.QEraseSegment[segment]};

GetSegmentInfo: PUBLIC ENTRY PROC[
segment: Segment] RETURNS [filePath: ROPE, number: NAT, trans: Transaction,
readOnly: BOOL, nBytesInitial, nBytesPerExtent: INT] = TRUSTED
{ ENABLE UNWIND => NULL;
[filePath, number, trans, readOnly, nBytesInitial, nBytesPerExtent]←
DBModel.QGetSegmentInfo[segment];
RETURN[filePath, number, trans, readOnly, nBytesInitial, nBytesPerExtent] };

TransactionOf: PUBLIC PROC[segment: Segment] RETURNS [Transaction] =
{ RETURN[GetSegmentInfo[segment].trans] };

GetSegments: PUBLIC PROC RETURNS [sl: LIST OF Segment] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QGetSegments[]]};

-- *** Part 2: Schema-definition operations [DBModelGlobalImpl]

DeclareDomain: PUBLIC ENTRY PROC [
name: ROPE, segment: Segment,
version: Version← NewOrOld, estRelships: INT← 5] RETURNS [Domain] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QDeclareDomain[name, segment, version, estRelships]]};

DeclareRelation: PUBLIC ENTRY PROC [
name: ROPE, segment: Segment, version: Version← NewOrOld] RETURNS [Relation] = TRUSTED
 { ENABLE UNWIND => NULL;
  RETURN[DBModel.QDeclareRelation[name, segment, version]]};

DeclareAttribute: PUBLIC ENTRY PROC [
r: Relation, name: ROPE, type: DataType,
uniqueness: Uniqueness, length: INT, link: LinkType, version: Version← NewOrOld]
RETURNS[Attribute] = TRUSTED
 { ENABLE UNWIND => NULL;
  RETURN[DBModel.QDeclareAttribute[r, name, type, uniqueness, length, link, version]]};  

DeclareIndex: PUBLIC ENTRY PROC [
r: Relation, order: AttributeList, version: Version] RETURNS[Index] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QDeclareIndex[r, order, version]]};

DestroyDomain: PUBLIC ENTRY PROC [d: Domain] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDestroyDomain[d]};

DeclareSubType: PUBLIC ENTRY PROC [of, is: Domain] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDeclareSubType[of, is]};

DestroyRelation: PUBLIC ENTRY PROC [r: Relation] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDestroyRelation[r]};

DestroySubType: PUBLIC ENTRY PROC [of, is: Domain] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDestroySubType[of, is]};


-- *** Part 3: Primitive operations [DBModelBasicImpl]

FetchEntity: PUBLIC ENTRY PROC[d: Domain, name: ROPE, segment: Segment← NIL]
RETURNS[e: Entity] = TRUSTED
 { ENABLE UNWIND => NULL; DBStats.Starting[DeclareEntity];
  e← DBModel.QFetchEntity[d, name, segment]; DBStats.Stopping[DeclareEntity]};

DeclareEntity: PUBLIC ENTRY PROC[d: Domain, name: ROPE, version: Version← NewOrOld]
RETURNS[e: Entity] = TRUSTED
 { ENABLE UNWIND => NULL; DBStats.Starting[DeclareEntity];
  e← DBModel.QDeclareEntity[d, name, version]; DBStats.Stopping[DeclareEntity]};

DeclareRelship: PUBLIC ENTRY PROC[r: Relation, init: AttributeValueList← NIL, version: Version← NewOrOld]
RETURNS[t: Relship] = TRUSTED
 { ENABLE UNWIND => NULL; DBStats.Starting[DeclareRelship];
  t← DBModel.QDeclareRelship[r, init, version]; DBStats.Stopping[DeclareRelship]};

DestroyEntity: PUBLIC ENTRY PROC[e: Entity] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDestroyEntity[e]};

DestroyRelship: PUBLIC ENTRY PROC[t: Relship] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QDestroyRelship[t]};

SetF: PUBLIC ENTRY PROC[t: Relship, a: Attribute, v: Value] = TRUSTED
{ ENABLE UNWIND => NULL; DBStats.Starting[SetF];
DBModel.QSetF[t, a, v]; DBStats.Stopping[SetF];};

SetFS: PUBLIC ENTRY PROC [t: Relship, a: Attribute, v: ROPE] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QSetFS[t, a, v]};

GetF: PUBLIC ENTRY PROC[t: Relship, a: Attribute] RETURNS [Value] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QGetF[t, a]]};

GetFS: PUBLIC ENTRY PROC[t: Relship, a: Attribute] RETURNS [ROPE] = TRUSTED
 { ENABLE UNWIND => NULL; RETURN[DBModel.QGetFS[t, a]]};

NameOf: PUBLIC ENTRY PROC [e: Entity] RETURNS [s: ROPE] = TRUSTED
 { ENABLE UNWIND => NULL; RETURN[DBModel.QNameOf[e]]};

ChangeName: PUBLIC ENTRY PROC [e: Entity, name: ROPE] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QChangeName[e, name]};

DomainOf: PUBLIC ENTRY PROC[e: Entity] RETURNS [Domain] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QDomainOf[e]]};

RelationOf: PUBLIC ENTRY PROC[t: Relship] RETURNS [Relation] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QRelationOf[t]]};

SegmentOf: PUBLIC ENTRY PROC[x: EntityOrRelship] RETURNS [Segment] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QSegmentOf[x]]};

-- *** Part 4: Aggregate operations [DBModelSetImpl]

RelationSubset: PUBLIC ENTRY PROC[
r: Relation, constraint: AttributeValueList← NIL,
start: FirstLast← First, searchSegment: Segment← NIL]
RETURNS [rs: RelshipSet] = TRUSTED
 { ENABLE UNWIND => NULL; DBStats.Starting[RelationSubset];
rs← DBModel.QRelationSubset[r, constraint, start, searchSegment];
  DBStats.Stopping[RelationSubset]};

NextRelship: PUBLIC ENTRY PROC[rs: RelshipSet] RETURNS [t: Relship] = TRUSTED
{ ENABLE UNWIND => NULL;
DBStats.Starting[NextRelship];
t← DBModel.QNextRelship[rs];
DBStats.Stopping[NextRelship]};

PrevRelship: PUBLIC ENTRY PROC[rs: RelshipSet] RETURNS [t: Relship] = TRUSTED
{ ENABLE UNWIND => NULL;
DBStats.Starting[PrevRelship];
t← DBModel.QPrevRelship[rs];
DBStats.Stopping[PrevRelship]};

ReleaseRelshipSet: PUBLIC ENTRY PROC [rs: RelshipSet] = TRUSTED
{ENABLE UNWIND => NULL; DBStats.Inc[ReleaseRelshipSet]; DBModel.QReleaseRelshipSet[rs]};

DomainSubset: PUBLIC ENTRY PROC[
d: Domain, lowName, highName: ROPE, start: FirstLast,
searchSubDomains: BOOL, searchSegment: Segment← NIL] RETURNS [es: EntitySet] = TRUSTED
{
ENABLE UNWIND => NULL;
DBStats.Starting[DomainSubset];
es← DBModel.QDomainSubset[d, lowName, highName, start, searchSubDomains, searchSegment];
DBStats.Stopping[DomainSubset];
RETURN[es] };

NextEntity: PUBLIC ENTRY PROC[es: EntitySet] RETURNS [e: Entity] = TRUSTED
{ ENABLE UNWIND => NULL;
DBStats.Starting[NextEntity];
e← DBModel.QNextEntity[es];
DBStats.Stopping[NextEntity];
};

PrevEntity: PUBLIC ENTRY PROC[es: EntitySet] RETURNS [e: Entity] = TRUSTED
{ ENABLE UNWIND => NULL;
DBStats.Starting[PrevEntity];
e← DBModel.QPrevEntity[es];
DBStats.Stopping[PrevEntity];
};

ReleaseEntitySet: PUBLIC ENTRY PROC[es: EntitySet] = TRUSTED
{ ENABLE UNWIND => NULL; DBStats.Inc[ReleaseEntitySet]; DBModel.QReleaseEntitySet[es]};

GetAllRefAttributes: PUBLIC ENTRY PROC [e: Entity] RETURNS [AttributeList] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QGetAllRefAttributes[e]]};

GetDomainRefAttributes: PUBLIC ENTRY PROC[d: Domain] RETURNS[al: AttributeList] = TRUSTED
{ ENABLE UNWIND => NULL;
  DBStats.Starting[GetDomainRefAttributes];
al← DBModel.QGetDomainRefAttributes[d];
DBStats.Stopping[GetDomainRefAttributes];
};


-- *** Part 5: Miscellaneous operations

-- Properties

DeclareProperty: PUBLIC ENTRY PROC [
relationName: ROPE, of: Domain, is: DataType, segment: Segment,
uniqueness: Uniqueness← None, version: Version← NewOrOld] RETURNS [aIs: Attribute] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QDeclareProperty[relationName, of, is, segment, uniqueness, version]]};

GetP: PUBLIC ENTRY PROC [e: Entity, aIs: Attribute, aOf: Attribute] RETURNS [v: Value] = TRUSTED
{ ENABLE UNWIND => NULL; DBStats.Starting[GetP];
v← DBModel.QGetP[e, aIs, aOf]; DBStats.Stopping[GetP]};

SetP: PUBLIC ENTRY PROC[
e: Entity, aIs: Attribute, v: Value, aOf: Attribute] RETURNS[t: Relship] = TRUSTED
{ ENABLE UNWIND => NULL; DBStats.Starting[SetP];
t← DBModel.QSetP[e, aIs, v, aOf]; DBStats.Stopping[SetP];};

GetPList: PUBLIC ENTRY PROC [e: Entity, aIs: Attribute, aOf: Attribute] RETURNS [vl: LIST OF Value] = TRUSTED
{ ENABLE UNWIND => NULL; RETURN[DBModel.QGetPList[e, aIs, aOf]]};

SetPList: PUBLIC ENTRY PROC[e: Entity, aIs: Attribute, vl: LIST OF Value, aOf: Attribute] = TRUSTED
{ ENABLE UNWIND => NULL; DBModel.QSetPList[e, aIs, vl, aOf]};

EntitySetToList: PUBLIC ENTRY PROC[es: EntitySet] RETURNS [el: LIST OF Entity] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QEntitySetToList[es]]};

RelshipSetToList: PUBLIC ENTRY PROC[rs: RelshipSet] RETURNS [rl: LIST OF Relship] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModel.QRelshipSetToList[rs]]};

IsSystemEntity: PUBLIC ENTRY PROC[e: Entity] RETURNS[BOOL] = TRUSTED
{ ENABLE UNWIND => NULL;
RETURN[DBModelPrivate.IsSystem[DBModelPrivate.T2CT[e]]]};

-- The following will be removed later

NameToEntity: PUBLIC ENTRY PROC[name: ROPE] RETURNS[e: Entity] = TRUSTED
-- Temporarily here. Copied from Donahue's DBNamesImpl.mesa.
{ ENABLE UNWIND => NULL;
segNameLength: INT = Rope.Find[ name, "!" ];
domainNameLength: INT = Rope.Find[ name, "!", segNameLength+1 ] - segNameLength - 1;
segName: ROPE = Rope.Substr[ name, 0, segNameLength ];
domainName: ROPE = Rope.Substr[ name, segNameLength+1, domainNameLength ];
entityName: ROPE = Rope.Substr[ name, segNameLength+domainNameLength+2 ];
segment: DB.Segment = Atom.MakeAtom[ segName ];
domain: Domain;
domain ← DBModel.QDeclareDomain[ domainName, segment, OldOnly !
    DB.Error => CHECKED { domain ← NIL; CONTINUE } ];
e ← IF domain = NIL THEN NIL
ELSE
DBModel.QFetchEntity[ domain, entityName, segment ] };

EntityToName: PUBLIC ENTRY PROC[e: Entity] RETURNS[name: ROPE] = TRUSTED
-- Temporarily here.
{ ENABLE UNWIND => NULL;
RETURN[Rope.Cat[
Atom.GetPName[DBModel.QSegmentOf[e]], "!",
DBModel.QNameOf[DBModel.QDomainOf[e]], "!",
DBModel.QNameOf[e] ]] };

PrintStats: PROC [heading: ROPE] = TRUSTED {
logStream: IO.STREAM← FS.StreamOpen["DB.Statistics", $create];
DBStats.Stopping[OpenToClose];
DBStats.Print[heading, logStream, FALSE];
DBStats.Initialize[];
logStream.Close[]; -- in case someone does checkpoint or something
};



END.