DIRECTORY AlpineEnvironment USING [LockOption], BasicTime USING[GMT], Basics USING[LowHalf], DBCommon, DBDefs, Rope USING[ROPE]; DB: CEDAR DEFINITIONS IMPORTS Basics = BEGIN ROPE: TYPE = Rope.ROPE; TypeCode: TYPE = DBDefs.TypeCode; FieldSpec: TYPE = REF FieldSpecObject; FieldSpecObject: TYPE = RECORD[fields: SEQUENCE count: CARDINAL OF Field]; TypeSpec: TYPE = RECORD[ type: SELECT kind: * FROM direct => [code: TypeCode], indirect => [ code: PROC[] RETURNS [TypeCode] ] ENDCASE ] _ Any; Field: TYPE = RECORD[name: ROPE, type: TypeSpec, lengthHint: CARDINAL _ 0]; Integer: TypeSpec = [direct[code: DBDefs.intType]]; String: TypeSpec = [direct[code: DBDefs.ropeType]]; Boolean: TypeSpec = [direct[code: DBDefs.boolType]]; Time: TypeSpec = [direct[code: DBDefs.timeType]]; Any: TypeSpec = [direct[code: DBDefs.anyDomainType]]; FieldSequence: TYPE = DBDefs.FieldSequence; ValueSequence: TYPE = DBDefs.ValueSequence; Value: TYPE = DBDefs.Value; Index: TYPE = DBDefs.Index; Segment: TYPE = DBCommon.Segment; SegmentList: TYPE = DBCommon.SegmentList; SegmentIndex: TYPE = DBCommon.SegmentIndex; FirstLast: TYPE = DBCommon.FirstLast; TransactionHandle: TYPE = DBCommon.TransactionHandle; Transaction: TYPE = DBCommon.Transaction; Domain: TYPE = DBDefs.Domain; DomainSet: TYPE = DBDefs.DomainSet; Relation: TYPE = DBDefs.Relation; RelationSet: TYPE = DBDefs.RelationSet; Entity: TYPE = DBDefs.Entity; EntitySet: TYPE = DBDefs.EntitySet; Relship: TYPE = DBDefs.Relship; Constraint: TYPE = DBDefs.Constraint; ValueConstraint: TYPE = DBDefs.ValueConstraint; RelshipSet: TYPE = DBDefs.RelshipSet; Error: ERROR [code: ErrorCode]; ErrorCode: TYPE = { AlreadyExists, -- DeclareEntity, DeclareRelship: already exists, but version=NewOnly BadUserPassword, -- Could not authenticate user CannotDefaultSegment, -- Segment name not built-in to Cypress, and no segment # given DatabaseNotInitialized, -- Attempt to perform operation without calling DB.Initialize EntityOrRelshipSetsOpen, -- Excessive Domain/RelationSubsets still open (CloseTransaction). DirectoryNotFound, -- Directory specified in segment name not found on file server FileNotFound, -- No existing segment found with given file name, and version=OldOnly InvalidSchema, -- The domain, relation, or attribute object being used is out of date IllegalAttribute, -- Attribute not of the given relship's Relation or not attribute IllegalConstraint, -- Constraint specification had value of incorrect type or had wrong length IllegalDomain, -- Argument is not actually a domain IllegalFileName, -- No directory or machine given for segment, or invalid chars in name IllegalEntity, -- Argument to GetP, or etc., is not an Entity IllegalIndex, IllegalKeySpecification, -- A field appears in two or more keys for a relation IllegalProperty, -- An attempt was made to declare a property relation with a non-entity valued first field IllegalRelation, -- Argument is not a relation IllegalString, -- Nulls not allowed in ROPEs passed to the database system IllegalSuperType, -- Can't define subtype of domain that already has entities MismatchedAttributeValueType, -- Value not same type as required (SetF) MismatchedExistingRelation, -- Existing relation is different (DeclareRelation) MismatchedExistingSegment, -- Existing segment has different # or name MismatchedValueType, MultipleMatch, -- More than one relationship satisfied avl on DeclareRelship. NonUniqueEntityName, -- Entity in domain with that name already exists NonUniqueKeyValue, -- Relship already exists with same value for a key attribute NotFound, -- Version is OldOnly but no such Entity, Relation, or etc found NotImplemented, -- Action requested is not currently implemented NILArgument, -- Attempt to perform operation on NIL argument NullifiedArgument, -- Entity or relationship has been deleted, or invalidated by trans abort ProtectionViolation, -- Read or write to segment file not permitted this user. QuotaExceeded, -- Database too big for Alpine page quota of segment's directory SegmentNotDeclared, -- Attempt to open transaction on segment with no DeclareSegment ServerNotFound, -- File server does not exist or does not respond TransactionNotOpen, -- Attempt to perform operation with no transaction open TransactionAlreadyOpen, -- Attempt to open transaction on segment already associated w/one WriteNotAllowed, -- Attempt to write data but DeclareSegment specified read-only WrongNumberOfFields, -- attempt to create relship with ill-formed list of initial values Unknown -- Unknown or not yet assigned error code }; Aborted: ERROR; Failure: ERROR [what: ATOM, info: ROPE]; Initialize: PROC[nCachePages: NAT _ 512, cacheFileName: ROPE _ NIL]; DeclareSegment: PROC[filePath: ROPE, segment: Segment, number: SegmentIndex _ 0, lock: AlpineEnvironment.LockOption _ [intendWrite, wait], readonly: BOOL _ FALSE, createIfNotFound: BOOL _ TRUE, nPagesInitial, nPagesPerExtent: INT _ 64]; EraseSegment: PROC[segment: Segment, useTrans: TransactionHandle _ NIL] RETURNS[trans: TransactionHandle]; GetSegmentInfo: PROC[Segment] RETURNS[filePath: ROPE, readOnly: BOOL]; OpenTransaction: PROC[segment: Segment, useTrans: TransactionHandle _ NIL] RETURNS[trans: TransactionHandle, schemaInvalid: BOOL]; SegmentsForTransaction: PROC[trans: TransactionHandle] RETURNS[SegmentList]; MarkTransaction: PROC[trans: TransactionHandle]; AbortTransaction: PROC[trans: TransactionHandle]; CloseTransaction: PROC[trans: TransactionHandle]; MakeTransHandle: PROC[trans: DBCommon.Transaction] RETURNS[handle: TransactionHandle]; DeclareDomain: PROC[name: ROPE, segment: Segment] RETURNS[d: Domain]; LookupDomain: PROC[name: ROPE, segment: Segment] RETURNS[d: Domain]; DestroyDomain: PROC[d: Domain]; DomainInfo: PROC[d: Domain] RETURNS[name: ROPE, segment: Segment]; NullDomain: PROC[d: Domain] RETURNS[BOOL]; DomainEq: PROC[d1, d2: Domain] RETURNS[BOOL]; DomainsByName: PROC[segment: Segment, lowName, highName: ROPE, start: FirstLast _ First] RETURNS[ds: DomainSet]; NextDomain: PROC[ds: DomainSet] RETURNS[d: Domain]; PrevDomain: PROC[ds: DomainSet] RETURNS[d: Domain]; ReleaseDomainSet: PROC[ds: DomainSet]; DeclareSubType: PROC[of, is: Domain]; DestroySubType: PROC[of, is: Domain]; SuperType: PROC[d: Domain] RETURNS[super: Domain]; SubTypes: PROC[d: Domain] RETURNS[subs: DomainSet]; TypeForDomain: PROC[d: Domain] RETURNS[type: TypeCode]; RelationsOf: PROC[d: Domain] RETURNS[rs: RelationSet]; DeclareRelation: PROC[name: ROPE, segment: Segment, fields: FieldSpec] RETURNS[r: Relation]; DeclareProperty: PROC[name: ROPE, segment: Segment, fields: FieldSpec] RETURNS[r: Relation]; LookupRelation: PROC[name: ROPE, segment: Segment] RETURNS[r: Relation]; FieldCount: PROC[r: Relation] RETURNS[count: CARDINAL]; Fields: PROC[r: Relation] RETURNS[fields: FieldSpec]; NameToField: PROC[r: Relation, name: ROPE] RETURNS[exists: BOOL, pos: CARDINAL]; FieldDescription: PROC[r: Relation, pos: CARDINAL] RETURNS[field: Field]; RelationInfo: PROC[r: Relation] RETURNS[name: ROPE, segment: Segment]; DestroyRelation: PROC [r: Relation]; NullRelation: PROC[r: Relation] RETURNS[BOOL]; RelationEq: PROC[r1, r2: Relation] RETURNS[BOOL]; RelationsByName: PROC[segment: Segment, lowName, highName: ROPE, start: FirstLast _ First] RETURNS[rs: RelationSet]; NextRelation: PROC[rs: RelationSet] RETURNS[Relation]; PrevRelation: PROC[rs: RelationSet] RETURNS[Relation]; ReleaseRelationSet: PROC[rs: RelationSet]; DeclareKeyIndex: PROC[r: Relation, fields: FieldSequence] RETURNS[index: Index]; DeclareIndex: PROC[r: Relation, fields: FieldSequence] RETURNS[index: Index]; KeyIndices: PROC[r: Relation] RETURNS[keyIndices: LIST OF Index]; OtherIndices: PROC[r: Relation] RETURNS[indices: LIST OF Index]; DestroyIndex: PROC[r: Relation, index: Index]; DeclareEntity: PROC[d: Domain, name: ROPE, newOnly: BOOL _ FALSE] RETURNS[e: Entity]; LookupEntity: PROC[d: Domain, name: ROPE] RETURNS[e: Entity]; DestroyEntity: PROC[e: Entity]; CopyEntity: PROC[e: Entity] RETURNS[Entity]; EntityInfo: PROC[e: Entity] RETURNS[name: ROPE, domain: Domain]; ChangeName: PROC[ of: Entity, to: Rope.ROPE ]; ToUnderType: PROC[e: Entity]; EntityEq: PROC[e1: Entity, e2: Entity] RETURNS[BOOL]; NullEntity: PROC[e: Entity] RETURNS[BOOL]; CreateRelship: PROC[r: Relation, init: ValueSequence] RETURNS[relship: Relship]; LookupRelship: PROC[r: Relation, keyIndex: Index, key: ValueSequence] RETURNS[relship: Relship]; LookupWithSimpleKey: PROC[r: Relation, keyIndex: Index, key: Value] RETURNS[relship: Relship]; LookupProperty: PROC[r: Relation, e: Entity] RETURNS[relship: Relship]; FirstRelship: PROC[r: Relation] RETURNS[relship: Relship]; DestroyRelship: PROC[t: Relship]; CopyRelship: PROC[t: Relship] RETURNS[Relship]; GetF: PROC[t: Relship, field: CARDINAL] RETURNS[Value]; SetF: PROC[t: Relship, field: CARDINAL, v: Value]; GetP: PROC[e: Entity, r: Relation, field: CARDINAL] RETURNS[Value]; SetP: PROC[e: Entity, r: Relation, field: CARDINAL, v: Value]; RelationOf: PROC[t: Relship] RETURNS[Relation]; RelshipEq: PROC[r1: Relship, r2: Relship] RETURNS[BOOL]; NullRelship: PROC[r: Relship] RETURNS[BOOL]; RelationSubset: PROC[r: Relation, index: Index, constraint: Constraint, start: FirstLast _ First] RETURNS[RelshipSet]; RelshipsForEntity: PROC[e: Entity] RETURNS[rs: RelshipSet]; RelshipsWithEntityField: PROC[r: Relation, field: CARDINAL, val: Entity] RETURNS[rs: RelshipSet]; NextRelship: PROC[rs: RelshipSet] RETURNS[Relship]; PrevRelship: PROC[rs: RelshipSet] RETURNS[Relship]; ReleaseRelshipSet: PROC[rs: RelshipSet]; DomainSubset: PROC[d: Domain, lowName, highName: ROPE _ NIL, start: FirstLast _ First] RETURNS[EntitySet]; NextEntity: PROC[es: EntitySet] RETURNS[Entity]; PrevEntity: PROC[es: EntitySet] RETURNS[Entity]; ReleaseEntitySet: PROC[es: EntitySet]; L2VS: PROC[vals: LIST OF Value] RETURNS[seq: ValueSequence]; L2FS: PROC[vals: LIST OF Field] RETURNS[seq: FieldSpec]; L2F: PROC[vals: LIST OF CARDINAL] RETURNS[seq: FieldSequence]; L2C: PROC[vals: LIST OF ValueConstraint] RETURNS[seq: Constraint]; I2V: PROC[i: INT] RETURNS[Value] = INLINE BEGIN RETURN[[integer[i]]] END; B2V: PROC[b: BOOL] RETURNS[Value] = INLINE BEGIN RETURN[[boolean[b]]] END; U2V: PROC[u: UNSPECIFIED] RETURNS[Value] = INLINE BEGIN RETURN[[integer[LOOPHOLE[u, CARDINAL]]]] END; S2V: PROC[s: ROPE] RETURNS[Value] = INLINE BEGIN RETURN[[rope[s]]] END; E2V: PROC[e: Entity] RETURNS[Value] = INLINE BEGIN RETURN[[entity[e]]] END; T2V: PROC[t: BasicTime.GMT] RETURNS[Value] = INLINE BEGIN RETURN[[time[t]]] END; V2B: PROC[v: Value] RETURNS[value: BOOL] = TRUSTED INLINE { WITH v: v SELECT FROM boolean => value _ v.value; ENDCASE => ERROR Error[MismatchedValueType] }; V2I: PROC[v: Value] RETURNS[value: INT] = TRUSTED INLINE { WITH v: v SELECT FROM integer => value _ v.value; ENDCASE => ERROR Error[MismatchedValueType] }; V2S: PROC[v: Value] RETURNS[value: ROPE] = TRUSTED INLINE { WITH v: v SELECT FROM rope => value _ v.value; ENDCASE => ERROR Error[MismatchedValueType] }; V2U: PROC[v: Value] RETURNS[value: UNSPECIFIED] = TRUSTED INLINE { WITH v: v SELECT FROM integer => value _ Basics.LowHalf[LOOPHOLE[v.value]]; ENDCASE => ERROR Error[MismatchedValueType] }; V2T: PROC[v: Value] RETURNS[value: BasicTime.GMT] = TRUSTED INLINE { WITH v: v SELECT FROM time => value _ v.value; ENDCASE => ERROR Error[MismatchedValueType] }; V2E: PROC[v: Value] RETURNS[value: Entity] = TRUSTED INLINE { RETURN[WITH v: v SELECT FROM entity => v.value, null => NIL, ENDCASE => ERROR Error[MismatchedValueType] ] }; END. 8DFile: DB.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Contents: Cedar program interface to Cypress database system Created by: Rick Cattell, July 8, 1981 (as DBView interface) Rick Cattell, November 8, 1983 10:20 am Eric Bier, August 7, 1981 15:30:15 Willie-Sue, February 22, 1985 9:18:47 am PST Donahue, May 28, 1986 11:55:46 am PDT Widom, September 6, 1985 2:16:58 pm PDT Basic definitions Types Most of these type definitions duplicate those found in the DBDefs and DBCommon interfaces to make things a little less confusing for clients. One day soon these will be turned into opaque definitions (probably) to make the code somewhat more modular Note: type specification may be a nullary procedure (rather than simply being a type code) so that the client can define the fields of a relation before all of the domains that it may depend on have been declared Errors Programming error by client The transaction on the segment manipulated by the last operation was aborted. It is necessary to call AbortTransaction ; OpenTransaction before performing any further operations on the segment Unrecoverable error, out of resources or bad disk Global operations Initializes the database system for use. Only one client may open an instance of the database package at a time. The Initialize operation is idempotent: subsequent calls after the first return with no effect. System parameters are initialized as follows: nCachePages says how many pages of virtual memory to use for the DB page cache cacheFileName says what file to use for the database cache (DBSegment.VM default) Declares a segment file whose full path name is filePath; the file is not actually opened until a transaction is opened for this segment. If createIfNotFound is true, the segment is created if it does not already exist (at the time of the OpenTransaction call). 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, Grapenut, Squirrel, Test), else see database administrator. This crock will be fixed in some near future implementation of Cypress, I hope! Until then, GetBuiltInSegments will at least give a list of the segments that have been hard-wired into Cypress. 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. nPagesInitial and nPagesPerExtent 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 Erases all the relations and domains in the given segment. The segment must have been declared. A new transaction on the segment is opened, committed, and returned. Returns information about the given segment. The filePath will be NIL if no such segment is declared. Assocates the client-supplied useTrans transaction (or a newly created one if useTrans = NIL) with all operations on the given segment. The opened transaction is returned to the client (useTrans if it's non-NIL); if schemaInvalid is TRUE, then any cached Domain or Relation object are invalid. 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 Returns all of the segments currently sharing the transaction Makes all of the interactions of the transaction permanent and starts a new transaction. Discard all changes since the last MarkTransaction (or OpenTransaction). Does MarkTransaction but leaves no transaction open. -- The next procedure allows the database transaction to be controlled from the outside. Make a transaction handle from an Alpine transaction. Schema-definition and -interrogation operations The Operations on Domains Creates a domain of this name in the given segment, or fetches it if it already exists. If the domain does not exist in the segment, then the result will be NIL 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. Returns the name of a domain and the segment it belongs to. True iff the domain has been nullified or is NIL Returns TRUE iff d1 and d2 reference the same domain in the same segment, or are both null. Provides a domain set that enumerates domains in the given segment. Enumerates only those domains whose name is lexicographically >= lowName and <= highName. The start parameter allows the enumeration to start at the beginning or end: If start = last, the enumeration will start with the domain with the lexicographically largest name, i.e. NextDomain will return NIL and successive calls to PrevDomain will return the domains. The converse is true if start=first. Returns NIL when no more domains in the set. Can be used to back up a DomainSet. Returns NIL when back to beginning. Should be called when client is finished with a DomainSet. 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. Destroys the subtype relationship between the two domains. Returns the supertype of a given domain (if one has been previously defined using DeclareSubType). Returns the subtypes of a given domain (if any have been previously defined using DeclareSubType). Maps the domain into the type code needed to declare attributes. Produce a set of all relations that (potentially) have fields that reference entities in the given domain. The Operations on Relations Creates a relation of the given name in the given segment. The FieldSpec gives a description of the fields that each tuple in the relation will have. The first field of the given field specifications must be entity-valued (and not of type anyDomainType); the first field is taken as a key for the relation. Note that the GetP and SetP operations can be used on relations that have been declared as properties. If no relation with the given name exists in the segment, then r will be NIL Return the number of fields in the relation r Return the description of all of the fields of relation r. Which field of the relation r has the specified name? If exists is FALSE, then the value of pos is meaningless Returns the name and type of the given field. Returns the name of a relation and the segment it belongs to Destroys a relation, and all of its relationships. True iff the relation has been nullified or is NIL Returns TRUE iff r1 and r2 reference the same relation in the same segment, or are both null. Provides a relation set that enumerates relations in the given segment. Enumerates only those relations whose name is lexicographically >= lowName and <= highName. The start parameter allows the enumeration to start at the beginning or end: If start = last, the enumeration will start with the relation with the lexicographically largest name, i.e. NextRelation will return NIL and successive calls to PrevRelation will return the relations. The converse is true if start = first. Returns NIL when no more relations in the set. Can be used to back up a RelationSet. Returns NIL when back to beginning. Should be called when client is finished with a RelationSet. The Operations on Indices Creates a key index on the given fields. No two relationships in the relation will have the same key  both keys and other client-specified indices can be used to perform efficient enumeration Creates an index on the given fields. Note: in the current implementation, indices cannot be created after tuples have been added to the relation. Returns a list of all of the indices maintained on keys of the relation. Returns a list of all non-key (client-specified) indices of the relation. Destroy a previously declared index. Primitive operations Creates or returns an existing entity in domain d with the given name. 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 EntityInfo. Errors: IllegalDomain if d is not a legal domain AlreadyExists if newOnly and the entity already exists in the domain If no entity exists with the given name in the domain, e will be NIL. Errors: IllegalDomain if d is not a legal domain Removes entity from its domain and destroys all relationships referencing the entity. Creates a copy of an entity such that the tuple handle for the entity will NOT be nullified when the transaction for the segment in closed. This allows an application to cache entities across transaction commits or aborts: NOTE THAT IT IS THE CLIENT'S RESPONSIBILITY TO ENSURE THAT THE TUPLEHANDLE REMAINS VALID. Returns name of entity e and the domain it belongs to. Allowed on relation, attribute, and domain entities too. Changes the name of the Entity to be the given ROPE This NARROWs the entity to the subtype (if any) from which it came; if the domain of e has no subtypes then this operation has no effect. Note: THIS DOES NOT CREATE A NEW ENTITY, BUT CHANGES THE DOMAIN OF THE ONE SUPPLIED. Returns TRUE iff e1 and e2 reference the same entity in the same segment, or are both null. Returns TRUE iff e is NIL or has become invalidated by deletion or transaction abort. Creates a relationship in relation r with the given initial values. Return the relship (if any) that has the value sequence as the given key. The index must have been declared using DeclareKeyIndex If the key field is only one element long, this procedure can be used instead of the one above  it obviates some of the problems of sequences in Cedar. If the relation r was declared to be a property, then return the relationship that has e as its key. This returns the first relationship in the relation r; it is more efficient than the corresponding RelationSubset followed by NextRelship. This is particularly useful if the client can guarantee that the relation r contains only a single relationship Removes relationship from its relation and destroys it. Creates a copy of an relationship such that the tuple handle for the relationship will NOT be nullified when the transaction for the segment in closed. This allows an application to cache relationships across transaction commits or aborts: NOTE THAT IT IS THE CLIENT'S RESPONSIBILITY TO ENSURE THAT THE TUPLEHANDLE REMAINS VALID. Returns the given attribute value. If the field is a nullified entity-valued field, then the value null[] is returned. Sets attribute a of relationship t to given numeric, string, or entity value. The value null[] can be used to nullify entity-valued fields If the relation r was defined as a property, then get the field of the relationship in r having e as its first attribute (ERROR DB.Error[NotFound] will be raised if no such relationship exists. (This is more efficient than the corresponding GetF[LookupProperty[ . . .] . . .]). If the relation r was defined as a property, then set the field of the relationship in r having e as its first attribute (ERROR DB.Error[NotFound] will be raised if no such relationship exists. (This is more efficient than the corresponding SetF[LookupProperty[ . . .] . . .]). Returns the relation to which the relationship belongs. Returns TRUE iff r1 and r2 reference the same relship in the same segment, or are both null. Returns TRUE iff r is NIL or has become invalidated by deletion or transaction abort. Aggregate operations 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 index and the constraints must match in size and the constraints must be consistent with the type of the index. The elements of the enumeration will be produced in the order in which they are found in the index. Note that this index may be either a key specification or another non-key client-specified index. Enumerate all of the relships that reference e in some field. These relationships may span a number of different relations. Enumerate all of the relships that have the value val for the given field (where the field must be entity-valued). Even if the relation does not have a key on the given field, this enumeration will be fast. Returns NIL when there are no more entities in the set. Can be used to back up a RelshipSet. Returns NIL when back to beginning. Should be called when client is finished with a RelshipSet. Used with NextEntity to index through entities in a domain (if d is one of the system domains, then the segment argument is used to disambiguate). 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. Returns NIL when no more entities in the set. Can be used to back up an EntitySet. Returns NIL when back to beginning. Should be called when client is finished with an EntitySet, to release resources. Miscellaneous operations Converting from Lists to Sequences (why, oh why isn't this part of the language?) Conversion of values to and from Mesa types Use for storing an enumerated type such as Uniqueness as an INT Procedures to do implicit NARROWs. สd˜šœ ™ Icodešœ ฯmœ1™<—Jšœ<™<šœ<™˜MJšœŸ1˜FJšœŸ=˜PJšœ Ÿ@˜JJšœŸ0˜@Jšœ Ÿ/˜JšœE™EJšœ™Jšœ(™(—J˜š  œžœ ˜JšœV™V—J˜š  œžœ žœ ˜,Jšœบ™บ—J˜š  œžœ žœžœ˜@Jšœp™p—J˜š  œžœžœ˜.Jšœ3™3—J˜š  œžœ ˜Jšœ฿™฿—J˜š œžœžœžœ˜5Jšœ[™[—J˜š  œžœ žœžœ˜*JšœV™V—J™š  œžœ#žœ˜PJšœC™C—J˜š  œžœ3žœ˜`Jšœ‚™‚J˜—š œžœ+žœ˜^Jšœ˜™˜—J˜š œžœžœ˜GJšœd™d—J˜š  œžœžœ˜:Jšœ๛™๛—J˜š œžœ ˜!Jšœ7™7J˜—š  œžœ žœ ˜/Jšœห™ห—J˜š œžœžœžœ˜7Jšœv™vJ˜—š œžœžœ ˜2Jšœ‹™‹—J˜š œžœ žœžœ˜CJšœ•™•J˜—š œžœ žœ ˜>Jšœ–™–—J˜š  œžœ žœ ˜/Jšœ7™7J˜—š  œžœžœžœ˜8Jšœ\™\J˜—š  œžœ žœžœ˜,JšœV™V——šœ™š œžœNžœ ˜vJšœา™าJ˜—š œžœ žœ˜;Jšœ|™|—J˜š œžœžœžœ˜aJšœฯ™ฯ—J˜š  œžœžœ ˜3Jšœ7™7J˜—š  œžœžœ ˜3JšœI™IJ˜—š œžœ˜(Jšœ;™;J˜—š   œžœžœžœžœ ˜jJšœู™ูJ˜—š  œžœžœ ˜0Jšœ-™-J˜—š  œžœžœ ˜0JšœI™IJ˜—š œžœ˜&JšœQ™Q——šœ™L™QJš  œžœžœžœžœ˜J˜Jš  œžœžœžœžœ˜BLšœ+™+š œžœžœžœ ˜"Jšžœžœžœžœ˜&J˜—š œžœžœžœ ˜#Jšžœžœžœžœ˜&J˜—š œžœž œžœ ˜*Jšœ?™?Jš žœžœžœ žœžœžœ˜:J˜—š œžœžœžœ ˜#Jšžœžœžœ žœ˜#J˜—š œžœ žœ ˜%Jšžœžœžœžœ˜%J˜—š œžœžœžœ ˜,Jšžœžœžœ žœ˜#—Lšœ"™"š œžœ žœžœ˜*Jš žœžœžœžœžœžœ˜qJ˜—š œžœ žœžœ˜)Jš žœžœžœžœžœžœ˜qJ˜—š œžœ žœžœ˜*Jš žœžœžœžœžœžœ˜nJ˜—š œžœ žœž œ˜1Jšžœžœžœžœ#žœ žœžœ˜‹J˜—š œžœ žœžœ˜3Jš žœžœžœžœžœžœ˜nJ˜—š œžœ žœ˜,Jšžœžœžœžœžœžœžœžœžœ ˜~—J˜—Jšžœ˜J˜—…—-Hv๐