-- File: DB.mesa
-- Contents: Cedar program interface to Cypress database system
-- Documentation: Probably [Indigo]<CedarDocs>Database>MLD.press, but see Rick Cattell.
-- Created by: Rick Cattell, July 8, 1981 (as DBView interface)
-- Last Edited by:
-- Rick Cattell, June 6, 1983 3:11 pm
-- Eric Bier, August 7, 1981 15:30:15
-- Willie-Sue, February 3, 1983 11:25 am

-- Table of Contents:
-- *** Part 1: Basic primitive type definitions: Entity, Value, Relship
-- *** Part 2: Global top-level operations: Initialize, DeclareSegment, OpenTransaction, etc.
-- *** Part 3: Schema-definition operations: DeclareDomain, DeclareRelation, etc.
-- *** Part 4: Primitive operations: GetF, SetF, DeclareEntity, DeclareRelship, etc.
-- *** Part 5: Aggregate operations: DomainSubset, RelationSubset, etc.
-- *** Part 6: Miscellaneous types and operations: value conversion, properties


DIRECTORY
Inline,
Rope,
System,
DBEnvironment;

DB: CEDAR DEFINITIONS IMPORTS Inline, DBEnvironment = BEGIN

ROPE: TYPE = Rope.ROPE;


-- *** Part 1: Basic primitive type definitions

-- The three types of basic objects:

Entity: TYPE = REF EntityObject;
-- The database equivalent of ATOM: represents some real or abstract object.
Value, Datum: TYPE = REF ANY;
-- Value may be ROPE, LONG INTEGER, or Entity. Datum is same except may not be Entity.
Relship: TYPE = REF RelshipObject;
-- A relationship between entities / values: a tuple of attributes = one row of a table.

EntityObject: TYPE = DBEnvironment.TupleObject;
RelshipObject: TYPE = DBEnvironment.TupleObject;
EntityOrRelship: TYPE = REF DBEnvironment.TupleObject; -- Supertype of Entity & Relship

-- The following entities represent TYPEs of Entities, Relships, etc.

Domain: TYPE = Entity; -- A type of Entity
Relation: TYPE = Entity; -- A type of Relship
Attribute: TYPE = Entity; -- A type of Relship field
DataType: TYPE = Entity; -- A type of Datum: one of the built-in types IntType, StringType, etc.
ValueType: TYPE = Entity; -- A type of Value: this type is a supertype of DataType and Domain
Index: TYPE = Entity; -- An index
IndexFactor: TYPE = Entity; -- An index factor

-- Values may be of simple data types such as IntType, or may be entities from domains.
-- Value types are used by attributes to specify what kind of values their fields may
-- contain; run-time type checking is performed when attributes of a relationship are set.
-- The special type AnyDomainType may be used for attributes that may refer to entities
-- in any domain.

StringType: DataType; -- A ROPE
IntType: DataType; -- An REF INT
BoolType: DataType; -- A REF BOOL
TimeType: DataType; -- A REF GreenwichMeanTime
AnyDomainType: DataType; -- An Entity of an unknown domain.
RecordType: DataType; -- Not yet for use by clients

-- Error signals: see DBEnvironment for definition of error codes. Error and InternalError
-- are defined as SIGNALs instead of ERRORs mainly so wizards can resume errors if they
-- know what they are doing; be forewarned that at some future date they may no longer
-- be resumeable.

Error: SIGNAL[code: DBEnvironment.ErrorCode]; -- Logical or programming error by client

Aborted: ERROR [trans: REF ANY]; -- Transaction reset: call AbortTransaction, OpenTransaction to proceed

Failure: PUBLIC ERROR[what: ATOM, info: ROPE]; -- Unrecoverable error, out of resources or bad disk

InternalError: PUBLIC SIGNAL; -- Bug in database system, hardware, or operating system

-- Data Structures to aid in queries: used by RelationSubset and DomainSubset

AttributeValueList: TYPE = LIST OF AttributeValue;
AttributeValue: TYPE = RECORD [
attribute: Attribute,
lo: Value,
hi: Value← NIL]; -- hi defaults to lo

AttributeList: TYPE = LIST OF Attribute;

EntitySet: TYPE = REF EntitySetObject;
EntitySetObject: TYPE;

RelshipSet: TYPE = REF RelshipSetObject;
RelshipSetObject: TYPE;

-- Miscellaneous type definitions

Transaction: TYPE = REF ANY;
-- May be a DBEnvironment.PilotTrans or DBEnvironment.AlpineTrans.

Segment: TYPE = ATOM;

Version: TYPE = DBEnvironment.Version; -- {OldOnly, NewOnly, NewOrOld};
FirstLast: TYPE = DBEnvironment.FirstLast; -- {First, Last};
Uniqueness: TYPE = {None, Key, KeyPart, OptionalKey};
LinkType: TYPE = {Linked, Unlinked, Colocated, Remote, None};

-- The system-defined domains, relations, and attributes (grouped by domains).
-- These are used only by programs that wish to examine a data schema, e.g.
-- application-independent browsing or query facilities; they are described in
-- more detail in the documentation. Implementors of specific-purpose database
-- applications may skip to Part 2 at this point.

DomainDomain: PUBLIC READONLY Domain; -- el'ts of this domain returned by DeclareDomain

dSubType: PUBLIC READONLY Relation; -- Specifies subtypes of domains (but not trans closure)
-- [
dSubTypeOf: Domain, dSubTypeIs: Domain]: returned by DeclareSubType
dSubTypeOf: PUBLIC READONLY Attribute; -- the super-type
dSubTypeIs: PUBLIC READONLY Attribute; -- the sub-type

RelationDomain: PUBLIC READONLY Domain; -- el'ts of this domain returned by DeclareRelation

AttributeDomain: PUBLIC READONLY Domain; -- el'ts of this domain returned by DeclareAttribute

-- The following relations pertain to attributes:

aRelation: PUBLIC READONLY Relation; -- Specifies correspondence between attributes & rel'ns:
-- [aRelationOf: KEY Attribute, aRelationIs: Relation]
aRelationOf: PUBLIC READONLY Attribute; -- the attribute whose relation we are specifying
aRelationIs: PUBLIC READONLY Attribute; -- the relation of that attribute

aType: PUBLIC READONLY Relation; -- Specifies type of relation attributes:
-- [aTypeOf: KEY Attribute, aTypeIs: ValueType]
aTypeOf: PUBLIC READONLY Attribute; -- the attribute
aTypeIs: PUBLIC READONLY Attribute; -- domain or datatype of the attribute

aUniqueness: PUBLIC READONLY Relation; -- Specifies whether attribute value must be unique:
-- [aUniquenessOf: KEY Attribute, aUniquenessIs: INT LOOPHOLE[Uniqueness]]
aUniquenessOf: PUBLIC READONLY Attribute; -- the attribute
aUniquenessIs: PUBLIC READONLY Attribute; -- INT for Uniqueness: 0=None, 1=Key, etc.

aLength: PUBLIC READONLY Relation; -- Specifies length of attributes:
-- [aLengthOf: KEY Attribute, aLengthIs: INT]
aLengthOf: PUBLIC READONLY Attribute; -- the attribute
aLengthIs: PUBLIC READONLY Attribute; -- INT corresponding to attribute's length

aLink: PUBLIC READONLY Relation; -- Specifies whether attribute is linked:
-- [aLinkOf: KEY Attribute, aLinkIs: INT LOOPHOLE[LinkType]]
aLinkOf: PUBLIC READONLY Attribute; -- the attribute
aLinkIs: PUBLIC READONLY Attribute; -- INT for LinkType: 0=Linked, 1=Unlinked, etc.

DataTypeDomain: PUBLIC READONLY Domain; -- StringType, BoolType, etc. are of this domain

-- Index and IndexFactor entities are created by DeclareIndex. They have no entity names.
IndexDomain: PUBLIC READONLY Domain; -- one entity of this domain per index
IndexFactorDomain: PUBLIC READONLY Domain; -- one index factor per attribute in the index

-- The following relations pertain to index factors:

ifIndex: PUBLIC READONLY Relation; -- Specifies the index factors for each index
-- [ifIndexOf: KEY IndexFactor, ifIndexIs: Index]
ifIndexOf: PUBLIC READONLY Attribute; -- the index factor
ifIndexIs: PUBLIC READONLY Attribute; -- index of the factor

ifAttribute: PUBLIC READONLY Relation; -- Specifies the attribute an index factor corresponds to
-- [ifAttributeOf: KEY IndexFactor, ifAttributeIs: Attribute]
ifAttributeOf: PUBLIC READONLY Attribute; -- the index factor
ifAttributeIs: PUBLIC READONLY Attribute; -- the attribute this factor represents


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

Initialize: PROC[
nCachePages: NAT← 512, nFreeTuples: NAT← 32,
cacheFileName: ROPENIL, augments: BOOLFALSE];
-- Initializes the database system for use. Only one client may open an instance of the
-- database package at a time.
-- System parameters are initialized as follows:
-- nCachePages says how many pages of virtual memory to use for the DB page cache
-- nFreeTuples says how many entity/relship handles to allocate a free list for
-- cacheFileName says what file to use for the database cache (DBSegment.VM default)
-- augments says whether to enable augment feature, allowing cross-segment SetFs

DeclareSegment: PROC[
filePath: ROPE, segment: Segment, number: NAT← 0, readonly: BOOLFALSE,
version: Version← OldOnly, nBytesInitial, nBytesPerExtent: INT← 32768 ];
-- Declares a segment file whose full path name (including extension .segment) is filePath.
-- The server, directory, and file name should be included in the segment name
-- (Except no directory for server "[Local]", then it uses the local Pilot volume).
-- The file is not actually opened until a transaction is opened for this segment.
-- Examples of filePaths: "[Juniper]<Cattell>Database" or "[Local]Foo". The semantics of
-- the version argument (which is not interpreted until the actual OpenTransaction) are:
-- NewOnly: create a new segment or re-initialize any existing one (careful!)
-- OldOnly: open existing segment, generate error FileNotFound if doesn't exist
-- NewOrOld: open segment if exists, else create new empty one.
-- A segment number must also be passed in if a new segment might be created. This number
-- may be defaulted for applications whose number has been added to the database
-- system's default table (Walnut, Hickory, Squirrel, Test), else see database administrator.
-- This crock will be fixed in some near future implementation of Cypress, I hope!
-- If readonly=TRUE, then no writes may be performed on data in the segment.
-- DeclareSegment may be called more than once, however the (resumable) warning Error
-- TransactionAlreadyOpen will be generated if a transaction is already open on the segment.
-- If version#NewOnly, these additional calls to DeclareSegment are no-ops. If
-- version=NewOnly, however, the segment file will be re-initialized on the
-- next call to OpenTransaction. nBytesInitial and nBytesPerExtent tell Cypress how to create
-- and extend the file size of the segment as needed for more data.
-- Errors:
-- IllegalFileName if directory or server name was omitted
-- TransactionAlreadyOpen if transaction already open

GetSegments: PROC RETURNS [LIST OF Segment];
-- Returns all the segments that have been declared.

GetSegmentInfo: PROC[Segment] RETURNS [filePath: ROPE, number: NAT, trans: Transaction];
-- Returns information about the given segment. The trans is NIL if no transaction is open.

OpenTransaction: PROC[
segment: Segment,
userName, password: ROPENIL,
useTrans: Transaction← NIL,
noLog: BOOLFALSE ];
-- Assocates the client-supplied useTrans transaction (or a newly created one if useTrans=NIL)
-- with all operations on the given segment. Opens a connection with a remote file server
-- if necessary to open the segment; this may require the user name and password. On Pilot,
-- useTrans may be a null transaction. On Alpine, noLog indicates whether an Alpine log
-- should be kept.
-- Errors:
-- TransactionAlreadyOpen if transaction is already associated with this segment (must close)
-- FileNotFound if a segment under this transaction (see DeclareSegment) not found
-- ProtectionViolation if a segment file under this transaction cannot be accessed
-- MismatchedExistingSegment if existing segment file has different number or name

MarkTransaction: PROC[trans: Transaction];
-- Makes all of the interactions of the transaction permanent and starts a new transaction.

AbortTransaction: PROC[trans: Transaction];
-- Causes system to forget all database changes made since the last MarkTransaction (or
-- since transaction was opened if no call to MarkTransaction has been made on trans).

CloseTransaction: PROC[trans: Transaction];
-- Does MarkTransaction but leaves no transaction open.

TransactionOf: PROC[segment: Segment] RETURNS [Transaction] =
-- Returns the transaction under which the segment is currently open, or NIL if
-- no transaction is open for the segment. Note that one can find the transaction
-- for a particular entity or tuple x by TransactionOf[SegmentOf[x]].
INLINE {RETURN[GetSegmentInfo[segment].trans]};

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

DeclareDomain: PROC [
name: ROPE, segment: Segment,
version: Version← NewOrOld, estRelships: INT← 5] RETURNS [Domain];
-- Creates a domain of this name in the given segment, or fetches it if it already exists.
-- Currently estRelships must be given to estimate the maximum number of attributes
-- that might reference an entity in this domain. Returns NIL if version=OldOnly and
-- no domain with the given name is found in the segment. Generates error
-- AlreadyExists if version=NewOnly and there is already a domain with this name.

DeclareRelation: PROC [
name: ROPE, segment: Segment,
version: Version← NewOrOld] RETURNS [Relation];
-- Creates a relation of the given name in the given segment, or fetches it if it
-- already exists. Returns NIL if version=OldOnly and no relation with
-- the given name is found in the segment. Generates the error
-- AlreadyExists if version=NewOnly and there is already a relation with this name.

DeclareAttribute: PROC [
r: Relation, name: ROPE, type: ValueType← NIL, uniqueness: Uniqueness ← None,
length: INT← 10, link: LinkType← Linked, version: Version← NewOrOld]
RETURNS[Attribute];
-- Creates an attribute of relation r with the given name, or fetches it if it already exists.
-- The type may be StringType, IntType, etc., for simple datum-valued attributes.
-- The type is the Domain of the referenced entities for entity-valued attributes.
-- The uniqueness says whether this attribute's value is unique across the relation (Key),
-- or unique in combination with other attributes of uniqueness KeyPart.
-- The length hint is used only for StringType attributes, and is a hint how many
-- bytes to reserve for this field (though the length is allowed to exceed this).
-- The link hint is used only for entity-valued attributes, and indicates whether to
-- represent this attribute by pointers through the relationships referencing an entity (Linked),
-- or by storing the entity name in this attribute (Unlinked). The other two LinkTypes
-- (Colocated, Remote) are not yet implemented at this time. DeclareAttribute returns
-- NIL if version=OldOnly and no such attribute of this relation already exists.
-- Errors:
-- IllegalRelation if r is not a relation.
-- AlreadyExists if version=NewOnly and there is already an attribute with this name.
-- MismatchedExistingAttribute if attribute exists and the type, length, or uniqueness
-- mismatches the existing attribute's (however these are not checked if type=NIL). 

DeclareSubType: PROC [of, is: Domain];
-- Defines a subtype relationship between two domains => entities of subtype
-- can participate in any attribute accepting entities of the supertype.
-- Currently, may not do this if "of" domain has any relations defined on it or any
-- tuples in it. The two domains must be in the same segment or error code
-- MismatchedSegment will be generated.

DeclareIndex: PROC [
r: Relation, order: AttributeList, version: Version← NewOrOld] RETURNS[Index];
-- Creates an index on the given attributes, to make RelationSubset go faster.
-- See auxiliary documentation or Rick Cattell for how to use indices effectively.

DestroyDomain: PROC [d: Domain];
-- Destroys a domain, all its entities, and all relationships that reference entities in d.
-- It is the client's responsibility to destroy any sub-domains if desired.

DestroyRelation: PROC [r: Relation];
-- Destroys a relation, and all of its relationships.

DestroySubType: PROC [of, is: Domain];
-- Destroys the subtype relationship between the two domains.


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

DeclareEntity: PROC[
d: Domain, name: ROPENIL, version: Version← NewOrOld] RETURNS [e: Entity];
-- Creates or returns existing an entity in domain d with the given name.
-- If no name is given for a new entity, then a unique one is automatically generated.
-- Returns NIL if version=OldOnly and no existing entity, creating no new one.
-- Case is not significant in comparing entity names for equality, however the letter cases
-- used when the entity is created will faithfully be returned by calls to NameOf.
-- Signals:
-- AlreadyExists if version=NewOnly and there exists entity in d with that name
-- IllegalDomain if d is a system domain (DomainDomain, RelationDomain, etc.)

DeclareRelship: PROC[
r: Relation, init: AttributeValueList← NIL, version: Version← NewOrOld] RETURNS [Relship];
-- Creates or returns an existing relationship in relation r with the given attribute values.
-- If version = NewOnly, creates a new relationship without checking to see if an existing
-- relationship has any of the given attribute values (except for attributes that are keys).
-- If version = OldOnly, looks for an existing relationship with the given attribute values, and
-- returns NIL if not found. Same action with version = NewOrOld, but if no existing
-- relationship is found, one is created with attributes matching the init list (the low values),
-- and it is returned. The init list should contain both low and high values (e.g., a value range
-- for ROPEs) only if version=NewOnly (see documentation of RelationSubset's
-- AttributeValueList for full specification of lookup). DeclareRelship may generate
-- the same signals as SetF if the init list is used to create a new relationship.
-- The error MultipleMatch is generated if more than one existing relationship matches init
-- and version#NewOnly (use RelationSubset if you want more than one relationship).

DestroyEntity: PROC[e: Entity];
-- Removes entity from its domain and destroys all relationships referencing the entity.

DestroyRelship: PROC[t: Relship];
-- Removes relationship from its relation and destroys it.

GetF: PROC[t: Relship, a: Attribute] RETURNS [Value];
-- Returns the given attribute value, an Entity, ROPE, REF INT, REF BOOL, etc.
-- Returns the undefined value for one of these types if attribute not yet initialized,
-- see documentation. Returns NIL if attribute references an entity in an un-opened segment.
-- Errors:
-- IllegalRelship if t is not a Relship.
-- IllegalAttribute if a is not an attribute or is not an attribute of t's relation.

GetFS: PROC[t: Relship, a: Attribute] RETURNS [ROPE];
-- Translates the given attribute value to a ROPE and returns it. Translation is as follows:
-- For StringType attributes, returned as is. For IntType attributes, turns the INT into
-- an integer string equivalent. For BoolType, returns "TRUE" or "FALSE".
-- For AnyDomainType attributes, returns Rope.Cat[d, ": ", n] where n is the name of the
-- entity referenced, and d is the name of its domain, or returns NIL if it references no entity.
-- For entity-valued attributes with link=Remote, returns Rope.Cat[s, ": ", d, ": ", n],
-- where n is the name of the entity, d is its domain name, and s is its segment name.
-- Does NOT try to open segment if the entity is in another segment, just returns this string.
-- For other entity-valued attributes, returns name of the entity referenced, or NIL if NIL.
-- May generate same errors as GetF.

SetF: PROC[t: Relship, a: Attribute, v: Value];
-- Sets attribute a of relationship t to given numeric, string, or entity value.
-- Errors:
-- IllegalRelship if t is not a relationship.
-- IllegalAttribute if a is not an attribute or is not an attribute of t's relations.
-- IllegalValue if v is not one of the value types Cypress recognizes (ROPE REF INT, etc.).
-- MismatchedAttributeValueType if v is not of the datatype or domain required by a.

SetFS: PROC [t: Relship, a: Attribute, v: ROPE];
-- Sets field of relationship to the given Rope value, translating v to the type of a using
-- the converse algorithm to GetFS above. May generate same signals as SetF, and also
-- generates error NotFound for entity-valued attributes if no entity can be found
-- with name v in the domain referenced by the attribute.

NameOf: PROC [e: Entity] RETURNS [s: ROPE];
-- Returns name of entity e. Allowed on relation, attribute, and domain entities too.

DomainOf: PROC[e: Entity] RETURNS [Domain];
-- Returns entity e's domain (or more precisely, it returns the entity which represents
-- e's domain).

RelationOf: PROC[t: Relship] RETURNS [Relation];
-- Returns the relation to which relationship rel belongs.

SegmentOf: PROC [x: EntityOrRelship] RETURNS [Segment];
-- Returns the segment in which x is stored.

Eq: PROC [e1: Entity, e2: Entity] RETURNS [BOOL];
-- Returns TRUE iff e1 and e2 reference the same entity in the same segment, or are both null.

Null: PROC [e: Entity] RETURNS [BOOL];
-- Returns TRUE iff e is NIL or has become invalidated by deletion or transaction abort.


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

RelationSubset: PROC[
r: Relation, constraint: AttributeValueList← NIL, start: FirstLast← First] RETURNS [RelshipSet];
-- Used with NextRelship below to index through relationships in a relation whose fields match
-- specified value ranges. A NIL constraint gives all of r. The ordering is unspecified,
-- unless an index has been declared on the attributes in the constraint, in which case the
-- result is lexicographically sorted on the concatenation of the indexed attribute values. The
-- start parameter allows lexicographically sorted relationships to be enumerated in increasing
-- or decreasing order: If start=last, the enumeration will start with the last relationship, i.e.
-- NextRelship will return NIL and successive calls to PrevRelship will return the relationships.
-- The converse is true if start=first. See the documentation for full specification of
-- functionality and performance hints.

NextRelship: PROC[rs: RelshipSet] RETURNS [Relship];
-- Returns NIL when there are no more entities in the set.

PrevRelship: PROC[rs: RelshipSet] RETURNS [Relship];
-- Can be used to back up a RelshipSet. Returns NIL when back to beginning.
-- See Rick for state of current implementation.

ReleaseRelshipSet: PROC [rs: RelshipSet];
-- Should be called when client is finished with a RelshipSet.

DomainSubset: PROC[
d: Domain, lowName, highName: ROPENIL, start: FirstLast ← First,
searchSubDomains: BOOLTRUE, searchSegment: Segment← NIL] RETURNS [EntitySet];
-- Used with NextEntity to index through entities in a domain. The searchSubDomains arg
-- says whether to search any Domains related to d through the SubType relation.
-- If d is a system domain, searchSegment says which segment to search; all are searched
-- if segment is NIL. The searchSegment arg is ignored on non-system domains.
-- If lowName and highName are non-NIL, enumerates only those entities whose name
-- is lexicographically >= lowName and <=highName. As with RelationSubset, the start
-- parameter allows the enumeration to start at the beginning or end: If start=last, the
-- enumeration will start with the entity with the lexicographically largest name, i.e.
-- NextEntity will return NIL and successive calls to PrevEntity will return the entities.
-- The converse is true if start=first. If only highName is NIL, it defaults to lowName,
-- i.e. we will search for the entity whose name exactly equals lowName.

NextEntity: PROC[es: EntitySet] RETURNS [Entity];
-- Returns NIL when no more entities in the set.

PrevEntity: PROC[es: EntitySet] RETURNS [Entity];
-- Can be used to back up an EntitySet. Returns NIL when back to beginning.
-- See Rick for state of current implementation.

ReleaseEntitySet: PROC[es: EntitySet];
-- Should be called when client is finished with an EntitySet, to release resources.

GetAllRefAttributes: PROC [e: Entity] RETURNS [AttributeList];
-- Finds all attributes that currently reference the entity e via some relationship.

GetDomainRefAttributes: PROC[d: Domain] RETURNS[al: AttributeList];
-- Finds attributes that could reference d; does not return AnyDomainType attributes,
-- but does return attributes referencing subdomains of d.


-- *** Part 6: Miscellaneous operations [DBModelBasicImpl]

-- Conversion of values to and from Mesa types

I2V: PROC [i: INT] RETURNS[REF INT] =
INLINE BEGIN RETURN[NEW[INT← i]] END;

B2V: PROC [b: BOOL] RETURNS[REF BOOL] =
INLINE BEGIN RETURN[NEW[BOOL← b]] END;

U2V: PROC [u: UNSPECIFIED] RETURNS [Value] =
-- Use for storing an enumerated type such as Uniqueness as an INT
INLINE BEGIN RETURN[NEW[INTLOOPHOLE[u, CARDINAL]]] END;

S2V: PROC [s: ROPE] RETURNS [Value] =
-- Needed because compiler doesn't automatically widen a rope into a value
INLINE BEGIN RETURN[s] END;

T2V: PROC [t: System.GreenwichMeanTime] RETURNS [Value] =
INLINE BEGIN RETURN[NEW[System.GreenwichMeanTime← t]] END;


-- Procedures to do implicit NARROWs. These can also be done by client NARROWs except
-- for V2E, which the client cannot currently do due to a problem with opaque types.

V2B: PROC[v: Value] RETURNS [BOOL] =
INLINE {RETURN[NARROW[v, REF BOOL]^]};

V2I: PROC [v: Value] RETURNS [INT] =
INLINE {RETURN[NARROW[v, REF INT]^]};

V2S: PROC [v: Value] RETURNS [ROPE] =
INLINE {RETURN[NARROW[v]]};

V2U: PROC [v: Value] RETURNS [UNSPECIFIED] =
INLINE {refI: REF INTNARROW[v]; RETURN[Inline.LowHalf[refI^]]};

V2T: PROC [v: Value] RETURNS [System.GreenwichMeanTime] =
INLINE {RETURN[NARROW[v, REF System.GreenwichMeanTime]^]};

V2E: PROC [v: Value] RETURNS [Entity];

VL2EL: PROC [vl: LIST OF Value] RETURNS [el: LIST OF Entity] = TRUSTED
INLINE {RETURN[LOOPHOLE[vl]]};


-- Properties: a convenience feature allowing the client to treat entities as records

DeclareProperty: PROC [
relationName: ROPE, of: Domain, is: ValueType, segment: Segment,
uniqueness: Uniqueness← None, version: Version← NewOrOld] RETURNS [p: Attribute];
-- Creates a new relation with the given name and segment, with two attributes
-- named "of" and "is". (The same result can be achieved by calling DeclareRelation
-- and DeclareAttribute, this is just a convenience feature.) The version argument
-- is treated as in DeclareRelation and DeclareAttribute, see their definitions
-- for its semantics. DeclareProperty returns the "is" attribute of the resulting relation,
-- with the given type and uniqueness.

-- In the following four procedures, the attributes aOf and aIs must be attributes of the
-- same relation or the signal MismatchedProperty is generated. The attribute aOf may be
-- defaulted if aIs's relation is binary, in which case it is assumed to be the other attribute
-- of the relation. (More generally, it may be defaulted even if the relation is not binary, to be
-- the first-defined attribute of the relation other than aIs). The following four procedures
-- may generate all the same signals as GetF and SetF for mismatch of value types, etc.

GetP: PROC [e: Entity, aIs: Attribute, aOf: Attribute← NIL] RETURNS [v: Value];
-- Retrieves the value of the aIs attribute of the Relship whose aOf attribute equals e.
-- Returns null value of the appropriate type if there is no such Relship.
-- Generates MultipleMatch if there is more than one such Relship.

SetP: PROC [e: Entity, aIs: Attribute, v: Value, aOf: Attribute← NIL] RETURNS [Relship];
-- If aOf is a Key or OptionalKey attribute, sets the value of the aTo attribute
-- of the relationship whose aOf attribute equals e, or creates such a relationship if
-- there is none such. If aOf is not a key, always creates a new relationship whose aOf
-- atribute equals e and whose aIs attribute equals v. Returns the existing or created
-- relationship for use by client.

SetPW: PROC [e: Entity, aIs: Attribute, v: Value, aOf: Attribute← NIL] =
-- Same as SetP, but doesn't return the existing or created Relship.
INLINE {[]← SetP[e, aIs, v, aOf]};

GetPList: PROC [
e: Entity, aIs: Attribute, aOf: Attribute← NIL] RETURNS [vl: LIST OF Value];
-- Returns list of the values of the aIs attributes of each Relship that references
-- e in attribute aOf.

SetPList: PROC [
e: Entity, aIs: Attribute, vl: LIST OF Value, aOf: Attribute← NIL];
-- Destroys any relationships that reference e in attribute aOf, and creates a new set of
-- relationships for each element of vl, whose aOf attribute is e and whose aIs attribute
-- is the corresponding element of vl. Note these semantics are not symmetric with SetF,
-- which may modify an existing relationship: SetPList is not generally useful on
-- non-binary relations, as it tosses attribute values other than aIs.


-- Advanced procedures and variables, mainly for use by general-purpose database tools

ChangeName: PROC[e: Entity, name: ROPE];
-- Changes the name of entity e to given name. Semantically equivalent to destroy the
-- entity and creating a new one with the new name and all the relationships referencing
-- the old one changed to reference the new one. May be used on relations, attributes,
-- and domains as well as normal entities.

FetchEntity: PROC[d: Domain, name: ROPE, segment: Segment← NIL] RETURNS [Entity];
-- Returns the unique entity with the given name. Works when d=DomainDomain
-- or RelationDomain, in which case segment argument is used to determine which
-- segment the domain or relation resides in. Also works to look up the Domain Domain
-- itself within itself, etc. Returns NIL if no such entity found.

MakeUndefined: PROC[vt: ValueType] RETURNS [Value];
-- Returns the unique "undefined" value for the given value type. At present, this is a 0 for
-- IntType, "" for StringType, FALSE for BoolType, NIL for entity types (domains).
-- The attributes of Relships of these types have these values until the first SetF.
-- Unfortunately, these values are very unique! At some future date we will change them
-- to be values not likely or possible to be used by client programs (e.g., -infinity for INT).

IsUndefined: PROC[v: Value] RETURNS [BOOL];
-- Returns TRUE iff the given value equals the distinguished undefined value for its type.
-- See comment above about undefined value assignment; use this proc to avoid future change.

IsSystemEntity: PROC[e: Entity] RETURNS [BOOL];
-- Returns TRUE iff the given entity is one of the system relations, domains, or attributes.

r1to1Prop: Attribute; -- indicates whether relation is actually stored with first attribute's entity


-- Items for backward compatibility with previous versions

EntitySetToList: PROC[es: EntitySet] RETURNS [el: LIST OF Entity];
-- Enumerates es and returns a list instead.

RelshipSetToList: PROC[rs: RelshipSet] RETURNS [rl: LIST OF Relship];
-- Enumerates rs and returns a list instead.

CreateEntity: PROC[d: Domain, name: ROPENIL] RETURNS [e: Entity] = INLINE
-- Creates new entity in with the given name.
{RETURN[DeclareEntity[d, name, NewOnly]]};

CreateRelship: PROC[r: Relation, init: AttributeValueList←NIL] RETURNS [Relship] = INLINE
-- Creates relship with the given attribute/value pairs.
{RETURN[DeclareRelship[r, init, NewOnly]]};

GetName: PROC[e: Entity] RETURNS[ROPE] = INLINE
{RETURN[NameOf[e]]};

SetName: PROC[e: Entity, name: ROPE] = INLINE
{ChangeName[e, name]};



END.


Change Log

Changed by Rick Cattell on 16-Aug-81 14:39:53
Added ERROR signals from DBTuples, at least some of them. Added default arguments to DeclareAttribute (so can use to look up attributes as well as create them), DomainSubset/RelationSubset (so can use to get all of domain or relation). V2I must return a REF INT instead of INT due to some Mesa compiler bug.

Changed by Rick Cattell on 6-Nov-81 12:54:44
Added Uniqueness scheme for attributes, removed old special1to1 scheme for relations. Redesigned property routines. Added Name Elements. Added Subtype scheme.

Changed by Rick Cattell on 29-Dec-81 14:20:59
Removed name elements, in favor of a more parsimonious scheme: define a 1-to-N NameElement relation between domains and existing binary relations. But i haven't time to implement this right now, so will add later when clean up user-visible system relations.

Changed by Rick Cattell on 18-Jan-82 18:16:25
Added NonUnique signals, made some ERRORs into SIGNALs.

Changed by Rick Cattell on 31-Jan-82 16:06:30
General cleanup of View Level. Removed GetP, SetP. Put all type definitions at beginning. Added more comments.

Changed by Rick Cattell on 19-Feb-82 9:26:47
Added DatabaseNotFound.

Changed by Rick Cattell on 9-Mar-82 9:24:47
Added MustSetKeyAttributeFirst, documentation for OpenDatabase.

Changed by Rick Cattell on May 22, 1982 3:38 pm
Added DeclareEntity, DestroySubType, Datum, DatabaseNotOpen, AttLoHiList=>AttributeValueList, PropertyLoHiList=>PropertyValueList, UpdateToDictionaryTuple=>UpdateToDictionaryInfo.

Changed by Rick Cattell on July 8, 1982 1:06 pm
Added RegisterUpdateProcs and friends. Added GetListP and SetListP, not yet implemented. Changed definition of Transaction to FileIO.Trans to avoid loopholes in client programs using files under same transaction.

Changed by Rick Cattell on July 16, 1982 5:58 pm: Recompiled for new Cedar. Added r1to1Prop, DeclareRelship.

Changed by Rick Cattell on October 29, 1982 2:31 pm: Too many interface items, according to compiler; removed AttHiLoList, RegisterUpdateProcs. May have to split up interface, or consolidate signals.

Changed by Rick Cattell on December 2, 1982 2:34 pm: conversion to new Model level.

Changed by Rick Cattell on December 18, 1982 12:38 pm: new segments, etc.

Changed by Rick Cattell on January 13, 1983 11:52 am: GetName => NameOf, added FetchEntity, and various other changes, all suggested by Jim Donahue.

Changed by Rick Cattell on February 3, 1983 10:59 am: Added better comments for system entities & relations.

Changed by Willie-Sue on February 3, 1983 11:25 am: Added noLog arg to OpenTransaction

Changed by Rick Cattell on February 11, 1983 9:50 am: random corrections & added undefined values.

Changed by Rick Cattell on March 15, 1983 9:24 am: Added FirstLast argument to DomainSubset and RelationSubset, and comments to describe its semantics.

Changed by Rick Cattell on March 16, 1983 4:06 pm: Added IsSystemEntity. Changed link argument of DeclareAttribute to allow other possibilities: Colocated, Remote. (These are not currently implemented.) Put in NameToEntity and EntityToName for now, may remove them later if implement Remote link.

Changed by Rick Cattell on April 12, 1983 10:01 am: Various changes. Removed some outdated procedures, version defaults in DeclareIndex, fixed some comments.

Changed by Cattell on June 6, 1983 2:50 pm: Added GetSegmentInfo, changed TransactionOf to INLINE. Added Failure signal and removed Fatal signal.