-- File: DBModelPrivate.mesa
-- Contents: Internal data structures and types for Model Level modules of Cedar DB.
-- File created by Rick Cattell, September 1980
-- Last edited by:
  -- Cattell on: November 8, 1983 11:10 am 
  -- Willie-Sue on January 27, 1983 2:04 pm      

DIRECTORY
  DB,
  DBStorage,
  DBModel,
  DBTuplesConcrete,
  DBEnvironment,
  Rope;
  
DBModelPrivate: DEFINITIONS
  IMPORTS
    DB,
    DBStorage,
    Rope
  SHARES DBModel

= BEGIN OPEN DB, DBTuplesConcrete;

-- Types

ROPE: TYPE = Rope.ROPE;
TupleHandle: TYPE = REF TupleObject;
TupleObject: TYPE = DBTuplesConcrete.TupleObject;
TupleSet, Attribute, Index, IndexFactor: TYPE = TupleHandle;
Value: TYPE = REF ANY;

AttributeValueList: TYPE = LIST OF AttributeValue;
AttributeValue: TYPE = DB.AttributeValue;
AttributeList: TYPE = DB.AttributeList;


-- Global variables and constants

MaxVTID: CARDINAL = DBStorage.MaxSystemTupleID;
MaxIndexKeyLength: CARDINAL = 200;
DefaultNameLength: INT = 12;
infString, minfSting: ROPE;

desperate: BOOL; -- Set to press on in spite of internal inconsistencies

-- Counts for balancing Subset/Release calls:

entitySetCount: PUBLIC INT;
relshipSetCount: PUBLIC INT;

defaultNameHandle: DBStorage.FieldHandle;
  -- name handle used for all domains w/ default naming: always first field, 18 chars
tupleSetNameHandle: DBStorage.FieldHandle;
  -- this one is used only for tuplesets (whose handle, not name, is first field)
attributeNameHandle: DBStorage.FieldHandle;
  -- this one is used only for attributes (whose name is first field, but is system tuple)
defaultNameAttribute: Attribute;
  -- fake attribute, not really used for much


-- Private system properties and relations, used internally and not exported to DB

dHandleProp: PUBLIC Attribute;
dIndexProp: PUBLIC Attribute;
rHandleProp: PUBLIC Attribute;
r1to1Prop: PUBLIC Attribute;
aHandleProp: PUBLIC Attribute;
aTypeCodeProp: PUBLIC Attribute;
aTypeEntityProp: PUBLIC Attribute;

aDomain: PUBLIC Relation; -- used to form group of attributes targetted to domain by surrogates
  aDomainOf: PUBLIC Attribute;
  aDomainIs: PUBLIC Attribute;

aUnlinked: PUBLIC Relation; -- used to form group of attributes that reference domain w/o link
  aUnlinkedOf: PUBLIC Attribute;
  aUnlinkedIs: PUBLIC Attribute;

ifOrdinalPosition: PUBLIC Relation; -- one element per index factor
  ifOrdinalPositionOf: PUBLIC Attribute; -- the index factor
  ifOrdinalPositionIs: PUBLIC Attribute;  -- INT: ordinal position in indexing



-- Definitions of system tuple (virtual) tids

NoTID: LONG CARDINAL = 0; -- used in tuple handles nullified by storage level

DomainTSID: LONG CARDINAL = 1;
RelationTSID: LONG CARDINAL = 2;
AttributeTSID: LONG CARDINAL = 3;
DataTypeTSID: LONG CARDINAL = 4;
IndexTSID: LONG CARDINAL = 5;
IndexFactorTSID: LONG CARDINAL = 6;

aRelationTSID: LONG CARDINAL = 7;
aTypeTSID: LONG CARDINAL = 8;
aUniquenessTSID: LONG CARDINAL = 9;
aLengthTSID: LONG CARDINAL = 10;
aLinkTSID: LONG CARDINAL = 11;
aDomainTSID: LONG CARDINAL = 12;
aUnlinkedTSID: LONG CARDINAL = 13;
ifIndexTSID: LONG CARDINAL = 14;
ifOrdinalPositionTSID: LONG CARDINAL = 15;
ifAttributeTSID: LONG CARDINAL = 16;
dSubTypeTSID: LONG CARDINAL = 17;

DummyID: LONG CARDINAL = 19; -- used for one fake relation

RopeTypeID: LONG CARDINAL = 20;
IntTypeID: LONG CARDINAL = 21;
TimeTypeID: LONG CARDINAL = 22;
BoolTypeID: LONG CARDINAL = 23;
RecordTypeID: LONG CARDINAL = 24;
AnyDomainTypeID: LONG CARDINAL = 25;

SurrogateRelshipID: LONG CARDINAL = 31; -- used for surrogate relships

FirstAttributeID: LONG CARDINAL = 32; -- system attribute ids are  32, 33, ...


-- Checking procedures

IsSystem: PROC[t: TupleHandle] RETURNS[BOOL] =
  INLINE {RETURN[t.tid<=DBStorage.MaxSystemTupleID AND t.tid#SurrogateRelshipID] };

IsSurrogate: PROC[t: TupleHandle] RETURNS[BOOL] =
  INLINE {RETURN[t.tid=SurrogateRelshipID] };

IsData: PROC[t: TupleHandle] RETURNS[BOOL] =
  INLINE BEGIN
  IF t.tid<MaxVTID THEN RETURN[FALSE]; -- system tuple
  RETURN[T2CT[DBStorage.ReadTupleset[LOOPHOLE[t]]].tid>=MaxVTID];
  END;

IsDictionary: PROC[t: TupleHandle] RETURNS[BOOL] =
  INLINE BEGIN
  IF t.tid<MaxVTID THEN RETURN[FALSE];
  RETURN[T2CT[DBStorage.ReadTupleset[LOOPHOLE[t]]].tid<MaxVTID];
  END;

IsDomainType: PROC [vt: DataType] RETURNS [b: BOOL];
  -- Returns TRUE iff vt is a domain or AnyDomainType

CheckEntity: PROC [t: TupleHandle];
  -- SIGNALS if t not an Entity

CheckRelship: PROC [t: TupleHandle];
 -- SIGNALS if t not a Relship

CheckDomain: PROC [d: Domain];
  -- Is d really a domain?  SIGNAL if not.

CheckRelation: PROC [r: Relation];
  -- Is r really a relation?  SIGNAL if not.

CheckAttribute: PUBLIC PROC [a: Attribute];
  -- Is a really an attribute?  SIGNAL if not.

CheckNIL: PROC[p: REF] = INLINE {
  -- Use for ROPEs and Values only.
  IF p=NIL THEN SIGNAL DB.Error[NILArgument] };

CheckNullified: PROC [p: TupleHandle] = INLINE {
  -- Use for Entities and Relships
  IF p=NIL THEN SIGNAL DB.Error[NILArgument]
  ELSE IF p.tid=NoTID THEN SIGNAL DB.Error[NullifiedArgument] };

CompatibleType: PROC [v: Value, t: DataType, fh: DBStorage.FieldHandle← NIL] RETURNS [BOOL];
  -- Returns TRUE if v's type is a built-in datatype identical to t or is a
  -- domain identical to t or a sub-domain of t.
  -- Takes the optional argument fh so can special-case aTypeProp.

CompatibleDomain: PUBLIC PROC [sub, super: Domain] RETURNS [BOOL];
  -- Returns TRUE iff sub=super or sub is related through transitive closure of
  -- SubType relations to super.  Should work with system sub or super.

IsKeyAttribute: PUBLIC PROC [a: Attribute] RETURNS [BOOL];

EmptyDomain: PUBLIC PROC [d: Domain] RETURNS [BOOLEAN];

EmptyRelation: PUBLIC PROC [r: Relation] RETURNS [BOOLEAN];


-- String manipulation procedures

ConvertToUpper: PUBLIC PROC[s: ROPE] RETURNS [ROPE];

StringToValue: PROC[s: ROPE, a: Attribute] RETURNS[v: Value];
  -- Converts a string to a value of the type required by a, doing the appropriate
  -- string conversion or a Fetch if dt is a Domain.

ParseSegmentName: PUBLIC PROC[path: ROPE] RETURNS [name, ext, server: ROPE];
  -- Separates [server]name.ext, and checks that name contains directory if non-local server
  
NCode: PUBLIC PROC[v: Value] RETURNS[ROPE];
  -- Converts value to encoded rope suitable for index lookup or matching.

CheckForNulls: PROC[s: ROPE] =
  INLINE BEGIN
  i: LONG CARDINAL← 0;
  last: LONG CARDINAL← Rope.Size[s];
  WHILE (i← i+1) < last DO
    IF Rope.Fetch[s,i]=0C OR Rope.Fetch[s,i]=377C THEN ERROR DB.Error[IllegalString] ENDLOOP;
  END;

MakeNullValueOfType: PUBLIC PROC [vt: DataType] RETURNS[Value];


-- Caching procedures.  These are designed to essentially all accesses to the data schema once
-- a database application is in some loop; the caches must be big enough to accomplish this
-- (see DBModelPrivateImpl), with considerable performance degradation if not.

GetCachedAttributeInfo: PUBLIC PROC[x: Attribute] RETURNS[
  relation: Relation, type: DataType, handle: DBStorage.FieldHandle,
  uniqueness: Uniqueness, link: LinkType, indexFactors: LIST OF IndexFactor];
  -- Returns all info set by DeclareAttribute, and also index factors x is connected to.
  
GetCachedRelationInfo: PUBLIC PROC[
  x: Relation] RETURNS[first, second: Attribute, indexes: LIST OF Index];
  -- Returns first and second attribute of x, and also any indexes on x.
  
GetCachedDomainInfo: PUBLIC PROC [x: Domain] RETURNS [
  surrogates, indexedSurrogates: LIST OF Relation,
  nameIndex: Index, subDomains: LIST OF Domain];
  -- Returns surrogate relations targetted to x, the subset of those that are indexed,
  -- the name index for x, and the subdomains of x.

GetCachedTupleTS: PUBLIC PROC[
  x: TupleHandle] RETURNS[TupleSet];
  -- Returns domain of entity or relation of relship.
  
FlushCaches: PROC;
  -- Flushes attribute, relation, tuple caches of info.  Must do if schema changes
  -- or transaction closed or aborted.

FlushTSCache: PROC;
  -- Just flushes the tupleset cache; should be called when tuple or entity destroyed.


-- Basic and Set operations on surrogates, system tuples (exported by Basic Impl)

SurrogateGetF: PROC[t: Relship, a: Attribute, string: BOOL] RETURNS [v: Value];
  -- Called by GetF to handle the surrogate relships.  If string=TRUE then fetch as StringType
  -- regardless of actual type.
 
SurrogateSetF: PROC[t: Relship, a: Attribute, v: Value];
 -- Called by SetF to handle the surrogate relships.
 
SurrogateCreateRelship: PROC[r: Relation, init: AttributeValueList← NIL] RETURNS[t: Relship];
  -- Creates a new surrogate relship in R, must set 1st attribute before others
   
SurrogateDestroyRelship: PROC [t: Relship];
  -- Destroys a surrogate relship (ie removes a property from an entity tuple)

SystemGetP: PROC[e: Entity, aIs: Attribute] RETURNS [v: Value];
  -- Call to handle system entities.

SafeGetP: PROC[e: Entity, aIs: Attribute] RETURNS [v: Value];
  -- Faster version of GetP which need not do type checking, for internal use only.

SafeSetP: PROC [e: Entity, aIs: Attribute, v: Value, aOf: Attribute← NIL] RETURNS[Relship];
  -- Same as SetP but doesn't do checking and works on dictionary entities.
  -- May return NIL for dictionary entities, for efficiency (client can't call, so doesn't matter).

SafeSetF: PROC [t: Relship, a: Attribute, v: Value];
  -- Same as SetF but doesn't do checking and works on dictionary relships.

SetValFromHandle:  PROC [
  t: Relship, fh: DBStorage.FieldHandle, ft: DataType, fl: LinkType← None, v: Value];
  -- Low level routine for actually doing field store (in BasicImpl)


-- System tuple operations (exported by System Impl)

SystemDomainSubset: PUBLIC PROC[
  d: Domain, lowName, highName: ROPE, segment: Segment] RETURNS [es: EntitySet];
  -- Call to handle system domains (RelationDomain or DomainDomain).

SystemRelationSubset: PUBLIC PROC[
  r: Relation, avl: AttributeValueList] RETURNS [rs: RelshipSet];
  -- Call to handle system relations.


-- Index- and link- related procedures (exported by Private Impl)

GetDomainIndex: PROC[s: Segment] RETURNS [Index];
  -- Returns the domain index for the segment

GetRelationIndex: PROC[s: Segment] RETURNS [Index];
  -- Returns the relation index for the segment

CreateEntityIndexEntries: PUBLIC PROC [e: Entity];
  -- Finds the name index for e's Domain and insert e into it.
  -- Also creates index entries for any surrogate relations that are actually stored in e.

DestroyEntityIndexEntries: PUBLIC PROC [e: Entity];  
  -- Find the name index for e's Domain and remove e from it.
  -- Also destroys any surrogate relation index entries.

DestroyVariableFieldsOf:  PUBLIC PROC[t: Relship];

DestroyLinksTo:  PUBLIC PROC[e: Entity];

DestroyLinksFrom:  PUBLIC PROC[t: Relship];

DestroyIndexEntries: PUBLIC PROC [t: Relship, changed: Attribute];

DestroyAllIndexEntries: PUBLIC PROC [t: Relship];

CreateIndexEntries: PUBLIC PROC [t: Relship, changed: Attribute];

CreateAllIndexEntries: PUBLIC PROC [t: Relship];

GetTypeAndLink: PUBLIC PROC [a: Attribute] RETURNS [type: Entity, link: LinkType];
  -- To get the type and link fields of an attribute, which are not stored explicitly.

SetTypeAndLink: PUBLIC PROC [a: Attribute, type: Entity, link: LinkType];
  -- To set the type and link fields of an attribute, which are not stored explicitly.


-- List and Set procedures (exported by Private Impl)

SearchEntityList: PROC [
  el: LIST OF Entity, test: PROC[Entity] RETURNS[BOOL]] RETURNS [Entity];

TransitiveClosure: PROC[e: Entity, from, to: Attribute] RETURNS [LIST OF Entity];
  -- Find all entities referenced by relships via the to attribute whose from attribute refns e,
  -- then all entities referenced by relships via the to attribute whose from
  -- attribute reference one of those, and so on, return the result as a list.

Nconc: PROC[l1, l2: LIST OF Entity] RETURNS [LIST OF Entity];
  -- Concatenates lists l1 and l2


-- Miscellaneous declarations (exported by Private Impl)

V2Rec: PROC[x: REF ANY] RETURNS [DBStorage.FieldHandle] = INLINE
  {RETURN[LOOPHOLE[x]]}; -- Can't do narrow because it's an opaque type!

T2CT: PROC[t: REF DBEnvironment.TupleObject] RETURNS [DBTuplesConcrete.TupleHandle] =
  INLINE BEGIN RETURN[LOOPHOLE[t]] END;

MakeFD: PROC [
  vt: DataType, length: INT← 0, link: BOOL← TRUE, a: Attribute← NIL]
  RETURNS [DBStorage.FieldDescriptor];

systemTupleVec: REF STSVecType;
STSVecType: TYPE = ARRAY[1..MaxVTID] OF TupleHandle;
  -- passed to storage level so that proper tuple can be returned when a GetF is done and the tid is < SL.MaxSystemTupleID.

SameSegment: PROC [x, y: DBStorage.TupleHandle] RETURNS [BOOL] = INLINE
  {RETURN[DBStorage.SegmentIDFromTuple[x]=DBStorage.SegmentIDFromTuple[y]]};

TranslateToSegment: PROC[e: Entity, of: TupleHandle] RETURNS[Entity];
  -- Returns e if it is already in the same segment as "of".  Otherwise, generates error, for now.
  -- In future this proc may automatically create an entity in the to segment.

InitializeSystemTuples: PROC;
  -- System relations are documented in DB.

NumberOfAttributes: PROC [r: Relation] RETURNS [n: CARDINAL];
  -- Returns the number of attributes r has.

GetFirstAttribute: PROC [
  of: Relation, notCounting: Attribute← NIL] RETURNS [a: Attribute];
  -- Returns the first attribute of relation "of" except for "notCounting".  Uses
  -- GetCacheRelationInfo to get attributes, unless "of" is a system relation.

FindSuperDomains: PROC[d: Domain] RETURNS [LIST OF Domain];
 -- Returns all super-Domains of d but not d itself.  Use GetCachedDomainInfo for sub-domains.


END.

Fix/extension records since 24-Nov-81:

Rick on 24-Nov-81 17:34:31: IsSurrogate[rel] returns FALSE because said tid=0 instead of SurrogateRelshipID.

Rick on 26-Nov-81 15:32:00: RopeToInt always returned an error, don't know why removed signed branch of case.

Rick on 29-Dec-81 14:47:31: Added TransitiveClosure and CompatibleType, removed TypeOf and some procs already in DBView.

Rick on April 28, 1982 9:54 am: Removed NCodeName, added NCode

Rick on May 22, 1982 6:56 pm: Added SafeSetP.  Added SetValFromHandle for DBViewGlobalImpl.

Rick on June 24, 1982 11:58 am: made FindSubDomains and FindSuperDomains non-inlines, changed FindSubDomains to work on AnyDomainType.

Rick on October 22, 1982 11:27 am: Changes for new properties and system relations.

Rick on December 19, 1982 12:58 pm: Re-organized and expanded, added DBModelPrivateImpl, new segment stuff, etc.  Added aDomain, aLink, aUnlinked, TranslateToSegment, many procedures previously in DBViewBasicImpl.

Rick on March 14, 1983 2:04 pm: expanded domain caching to include index & subdomains.