Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-05 - 43,50337/07/simdbm.rno
There is 1 other file named simdbm.rno in the archive. Click here to see a list.
.nojustify;.title A CODASYL-TYPE DBMS SYSTEM IN SIMULA
.nofill
Research Institute of National Defense########FOA 1 Report
Department 1##################################C10038-M3(E5)
10450 Stockholm 80############################August 1975
Sweden########################################Revised:
##############################################December 1977
.skip 3
A CODASYL-TYPE DBMS SYSTEM IN SIMULA
.left margin 5
.p -5,1,0
By Kalle M{kil{
.fill
.p -5,2,0
ABSTRACT: A CODASYL type Data Base Managment System (DBMS) has
.index Abstract
.index Summary
been written entirely in SIMULA. The system is called SIMDBM.
SIMDBM is fully usable in itself
for data bases of moderate size. It is especially suitable for education
about Data Base Managment, because of its simplicity and clarity.
The system is also an investigation into how an interface can be
arranged between the SIMULA programming language and a DBMS system.
There is a need both for a general purpose interface,
where the SIMULA program without change can handle any data base,
and a special purpose interface generated for a specific application,
in which data base RECORDs are directly mapped onto corresponding
SIMULA CLASS objects, with one CLASS attribute for each FIELD of
the data base RECORD.
.p -5,2,7
SEARCH KEY: SIMULA, ALGOL, Programming Language, Computer,
.index Search key
.index Keywords for this paper
Data Base, Data Base Managment System, DBMS, CODASYL group,
File Handling, Secondary Storage, Data Structure.
.p -5,2,7
SWEDISH ABSTRACT: Ett system f`r databashantering har skrivits helt i SIMULA.
Systemet kallas SIMDBM. Det {r fullt anv{ndbart f`r databaser av
m}ttlig storlek. Speciellt l{mpligt {r det f`r undervisning i
databashantering, eftersom det {r enkelt och logiskt till sin uppbyggnad.
Systemet har ocks} som syfte att utprova hur man kan utforma
ett interface mellan SIMULA och ett
databashanteringssystem. Det beh`vs b}de ett generellt interface
d{r ett SIMULA-program kan arbeta mot en godtycklig
databas utan att modifieras, och ett speciellt  d{r man kan
avbilda posterna i databasen p} klass-objekt med ett klassattribut
f`r varje dataf{lt i posten.

.page
Neither Kalle M{kil{ nor the Swedish National Defense Research Institute
take any responsibility for errors in this report or in the software
described.
.page;.indent -5
CONTENTS:
.index Contents list for this paper
.index List of contents for this paper
.index Contents, list of
.subtitle CONTENTS
.skip 2
1.##Introduction.
.left margin 21
.indent -5
1.1##Background.
.indent -5
1.2##Basic concepts.
.indent -5
1.3##Aspects which are considered important.
.indent -5
1.4##Aspects which may be important but are outside
the scope of this system.
.skip
.indent -16
2.##The Data Description.
.indent -5
2.1##What is a data description ?
.indent -5
2.2##How to create a data description.
.indent -5
2.3##How to make the description available within
a SIMULA program.
.skip
.left margin 11
.indent -6
3.##Facilities for manipulating the data base in a program.
.left margin 21
.indent -5
3.1##Summary of basic procedures for data manipulation.
.indent -5
3.2##How to write specific but very readable programs.
.indent -5
3.3##How to write general programs to be used on an
arbitrary data base.
.indent -5
3.4##Connection of own data structures to data retrieved
from the data base.
.indent -5
3.5##Concatenation of record types.
.skip
.left margin 11
.indent -6
4.##Comparison with a full CODASYL type system in
a COBOL environment.
.skip 2
.indent -11
APPENDICES:
.index Appendices in this paper, list of
.index Appendices, list of
.skip
.left margin 9
.indent -4
I###An example of a dialogue to create a data description.
.indent -4
II##An example of a specific SIMULA program using a data base.
.indent -4
III#Examples of SIMULA classes which can be generated
.indent -4
####automatically from the stored data description.
.indent -4
IV##Example of a general program which can be used
on any data base.
.indent -4
V###Description of classes for internal representation of
records and record specifications.
.indent -4
VI##Description of the main classes of the system.
.indent -4
VII#The use of several data bases in the same run.
.indent -4
VIII#Index.
.fill
.left margin 5
.subtitle INTRODUCTION
.page
.indent -5
1.#INTRODUCTION
.p -5,2,15
1.1#Background.
.p 0,2,5
This is the second edition of this report; the first edition
appeared in august 1975. Since then a radical redesign of the
system has been completed, and several useful utility programs have been
written to aid its use. These are described in another report
"Data base handling in SIMULA 67", and that report also contains some
more detailed technical information on the basic system.
That report is directed mainly to those who are actually using
SIMDBM, while this report deals with basic concepts. We have tried to
avoid purely technical matters in this report, but for those who find these
important for the understanding, we have added a number of
appendices with data structurres and examples of use.
.skip
Since the basic concepts in the system are the same as in the
first version, this report has not been very much changed, only
a few new features have been added.
.skip
We want to emphasize that  this document should not be regarded
as a users manual for SIMDBM. In fact there is no such manual,
but we hope that this report, in combination with the other report mentioned
 above
and the source code (which contains comments !) will make it possible to use.
In fact it has already been used in about seven different places
that we know of (and probably a few more that we don't know of).
.skip
The original version of SIMDBM was developed on the DEC-10
SIMULA compiler, but now there is also a version running on the
IBM370 SIMULA, and there are definite plans (in Germany
and the Netherlands) of installing it on CDC and UNIVAC computers.
.skip
SIMDBM is distributed for a small charge covering the costs
of the distribution (DEC10/DEC20 users can have it  via DECUS).
You could easily by a comparable data base handler for
about 200 000 swedish crowns, usually a bit more efficient, well
tested and documented, but often less flexible, without an interface
to a high level language such as SIMULA, and mostly without
a possibility to gain a full understanding of how the
system works on source code level.
.skip
We claim that SIMDBM is (and here we are supported by many persons who have
written asking for a copy) a useful complement to the commersially
available systems, at least for reseach and education.
.p -5,2,15
1.2#BASIC CONCEPTS
.p 0,2,5
This report describes a simple Data Base Managment System (DBMS)
based on the CODASYL Task Group (DBTG) proposal. The
.index DBMS system
.index Data Base Managment System
.index DBTG proposal for a DBMS
.index CODASYL Task Group proposal
DBMS system described is written entirely in the SIMULA programming
.index SIMULA programming language, use of
language. It was developed to test how an interface between SIMULA
.index Interface between SIMULA and a DBMS
.index SIMULA - DBMS interface
.index DBMS - SIMULA interface
and a DBMS system can be arranged. The same interface could then
be used when interfacing SIMULA to a larger DBMS system, not written
in SIMULA.
.p 0,2,5
Such an interface could use the same procedures to be
called from SIMULA and could map the data onto the same SIMULA-type
data structures in core. However, the actual procedures would of
course have to be rewritten.
.p
Our experience is that our DBMS system itself is fully usable
for applications of moderate size. It is
also, because of its simple structure, useful as a tool in teaching
.index Teaching about DBMS systems
.index Education about DBMS systems
data base managment techniques.
.p
Two central concepts in the DBTG proposal are those of a RECORD and
.index RECORD DBMS concet
.index SET DBMS concept
a SET.
.p
A RECORD is in some ways similar to a SIMULA CLASS. There can
be several types of RECORDs, each with a RECORD type name. The RECORD
is divided into FIELDs, which have a name and a type,
.index FIELD DBMS concept, similar to SIMULA CLASS attributes
.index Attributes of SIMULA CLASS, similar to DBMS FIELDs
just like CLASS attributes in SIMULA.
.p
A SET is a set of RECORDs. One RECORD is the OWNER of the SET. The other
.index SET DBMS concept
.index OWNER of a SET
.index MEMBER of a SET
RECORDs are called MEMBERs. The MEMBERs can be of more than one RECORD
type, and the number of MEMBERs can vary.
.p
SETs are often implemented by letting the OWNER refer to the first
MEMBER, that MEMBER to the next member etc. There must also be a
way of finding the OWNER from any of the MEMBERs. This is either
implemented by having a direct reference from each MEMBER to
the OWNER, or by letting the last MEMBER in the chain refer back to
the OWNER, so that the OWNER can be found indirectly by following
this chain from any of the MEMBERs.
.p
The SET concept can be used to create rather complex data structures
in the data base.
.no subtitle
.p -5,2,15
1.3#IMPORTANT ASPECTS IN THE DEVELOPMENT OF THE SYSTEM
.subtitle 1.2#IMPORTANT ASPECTS IN THE DEVELOPMENT OF THE SYSTEM
.p -5,2,7
#+++#The system should be easy to use for a person writing
an applications program.
.skip
The manuals for a CODASYL-type DBMS system can be very
.index Manuals, simple or difficult?
.index Easy to use DBMS systems
.index Difficult to use DBMS systems
.index GOALs in the design of SIMDBM
.index Aspects considered in the design of SIMDBM
.index CODASYL Task Group proposal
difficult to read, because of the many details.
A simple system can be a good introduction, and also be
enough in itself for many applications. For more advanced
applications, the system is easy to extend, since it is
.index Extendibility of the DBMS system
written entirely in SIMULA.
.p -5,2,7
#+++#Flexible data structures.
.skip
Data from the data base should be supplied in a form
suitable to the application program. A pre-processor
can be used to create SIMULA source program data structure
declarations, including procedures for reading and
writing data. These procedures will also convert
between the internal and external data format.
.p -5,2,7
#+++#Ways of extending the data base.
.index Extendibility of existing data bases
.skip
The user should have the facility both of adding new
RECORD types and to add more FIELDs to an existing
RECORD type. This should
not require any change in old programs using the data
base, and old data in the data base should still be readable.
.p -5,2,7
#+++#The application program should have available to it
a description of the data base structure.
.skip
This makes it possible to write fully general purpose
.index General-purpose, data independent application programs
.index Data independent application programs
.index Independent of data application programs
programs, which do not depend on the actual structure of the
data base. These programs will thus work for any data base,
independent of the actual RECORD types, SETs and
structures in that data base.
.skip
An example of such a program would be one, with which the
user at a conversational terminal can ask about
the structure of data, and allow him to read and write arbitrary
data within the structure of the data base.
.skip
Many commercial DBMS system do not have such a facility for
writing general-purpose programs in the high-level language.
.p -5,2,7
#+++#The code of the DBMS system itself should be easy to read and work with.
.skip
.index Source code of SIMDBM, readability of
.index Program source code of SIMDBM, readability of
.index Readability of source program code
Since the system is written entirely in the high-level language
SIMULA, it is also easy to move from one computer to another.
The system is also rather small (about 1100 lines SIMULA code),
.index Size of the SIMDBM system
.index SIMDBM system, size of
.index Length of the SIMDBM system
and we have carefully tried to keep it simple, clean and wellstructured.
.skip
This makes it possible for an experienced SIMULA programmer to
get control over the system, to modify and extend it.
.no subtitle
.p -5,2,15
1.4 IMPORTANT ASPECTS WHICH WE UNTIL NOW HAVE DISREGARDED.
.subtitle 1.3 IMPORTANT ASPECTS WHICH WE UNTIL NOW HAVE DISREGARDED
.p -5,2,7
#+++#High efficiency in the use of CPU-time and core.
.index Efficiency of core utilization and CPU utilization
.index Utilization effiency of core and CPU time
.index CPU time efficiency
.index Core utilization effiency
.index Memory utilization effiency
.skip
Certain effiency considerations have been made, but our main
goal has been to keep the program simple. The system can
probably be made very much faster by rewriting a few central
procedures in assembly language.
.p
#+++#Supporting several simultaneous users.
.index Simultaneous users, support of
.index Multi-user use of SIMDBM
.index Real time, multi-user use of SIMDBM
.index Several simultaneous users of SIMDBM
.skip
Every user program is a closed unit, which does not share code
with other people working against the data base. Several users
can simultaneously read the data base, but only one at a time
can write into it.
.p
#+++#Protection codes.
.index Protection of the data base
.index Data base security and protection
.index Security and protection of the data base
.skip
Codes to ensure security for parts of the data base has not
been introduced. This is however rather simple to add.
However, such codes are not necessary for many applications.
.no subtitle
.p -5,2,30
2.#THE SCHEMA (DATA BASE STRUCTURE DESCRIPTION)
.subtitle 2.#THE SCHEMA (DATA BASE STRUCTURE DESCRIPTION)
.index SCHEMA = data base structure description
.index Data Base Description
.no subtitle
.p -5,2,15
2.1 WHAT IS A SCHEMA?
.subtitle 2.1 WHAT IS A SCHEMA?
.p 0,2,5
A SCHEMA describes the structure of each RECORD type, and tells
which SETs each type of RECORD can be a MEMBER of.
Our SCHEMA is a simplification of that in the CODASYL proposal.
.index CODASYL Task Group proposal
.p
A RECORD consists of a number of FIELDs. Each FIELD
.index FIELDs of RECORDs, allowed types for
.index INTEGER type
.index REAL type
.index TEXT type
.index ARRAY kind of type
.index Length, variable, of TEXTs and ARRAYs
.index Variable length of TEXTs and ARRAYs
.index Arbitrary length of TEXTs and ARRAYs
.index Fixed length, #n#o#t,##of TEXTs and ARRAYs
.index TEXT length, variable
.index ARRAY length, variable
has a name and a type. Allowed types are: INTEGER, REAL, TEXT
and ARRAYs of these three types. The FIELDs have variable length,
but INTEGERs and REALs must be storable in one word in core.
.p
There is however no limit on the length of TEXTs or of the number
of elements in ARRAYs.
.p
A SET is characterized by three attributes:
.break
(a) The name of the SET, (b) The RECORD type of the OWNER,
(c) The allowed RECORD types of the MEMBERs.
The same RECORD type can be both OWNER and MEMBER of
a given SET.
.p
The SCHEMA is stored in the data base. There are two special
.index SCHEMA, storage in the data base of
.index Data Base Description, storage in the data base of
predefined RECORD types for this purpose, one for storing
.index Access to the SCHEMA from an applications program
the description of a RECORD and one for storing the
description of a SET. The SCHEMA is thus stored in
the same way as all other data in the data base. This makes
it simple for an applications program to create the description
of a new type of RECORD and store it into the SCHEMA in the data base.
.no subtitle
.p -5,2,15
2.2 HOW A SCHEMA IS CREATED
.index SCHEMA creation of
.index Data Base Description creation of
.index SPEC SCHEMA creation and modification program
.index DDL = Data Definition Language
.index Data Definition Language
.index OBJECT SCHEMA SEE SCHEMA
.subtitle 2.2 HOW A SCHEMA IS CREATED
.p 0,2,5
The first action when creating a new data base is to
make a SCHEMA and store it into the data base. To do
this in a simple way, the utility program SPEC can be
used. SPEC asks the user which RECORDs, FIELDs and SETs that
he wants to have in his data base.
.SKIP
     SPEC may not (due to an implementational restriction in
     the present version) be used to define sets in the same
     run as when the owner and member record types are
     specified.  So usually SPEC should be run twice (if
     sets are used), first for defining RECORDs and then for
     defining sets where those records are involved.
.p 0,2,5
SPEC makes it also possible to make certain changes to
an existing SCHEMA. The input to SPEC corresponds to the
Data Definition Language (DDL) in the CODASYL proposal.
.index CODASYL Task Group proposal
SPEC corresponds to the DDL processor and the SCHEMA
corresponds to the OBJECT SCHEMA.
.SKIP
     An example of a run with SPEC is given in Appendix I.
     It is intended to be reasonably selfinstructing, at
     each prompting question a question mark can be given to
     obtain help information.
.skip
It is also possible to specify that records of different types
shall be concatenated on retrieval. This is described in
section 3.5.
.SKIP
.no subtitle
.p -5,2,15
2.3 HOW TO ACCESS THE SCHEMA IN AN APPLICATIONS PROGRAM
.index Access to the SCHEMA from an applications program
.subtitle 2.3 HOW TO ACCESS THE SCHEMA IN AN APPLICATIONS PROGRAM
.p 0,2,5
Most CODASYL-systems do not seem to acknowledge the need
.index CODASYL Task Group proposal
for an application program to access the SCHEMA. All programming
requires exact knowledge of the SCHEMA, or rather of the
so-called SUB-SCHEMA. Our system also allows this kind of
.index SUBSCHEMA
.index SUB-SCHEMA
.index CLASSes mapping data base RECORDs
.index RECORD mapping into SIMULA CLASS objects
programming. The pre-processor PREP can be used.
.p
PREP asks
the user which parts of the data base that he wants access
to. (The answers to these questions thus correspond to the
SUB-SCHEMA.) The pre-processor will then produce a number
of SIMULA source program CLASS declarations, which are the
SIMULA representation of data from the data base.
.p
Each accessible RECORD TYPE in the data base is represented by
a SIMULA CLASS declaration, and each
accessible FIELD in the data base RECORD is
.index FIELD in RECORD corresponds to attribute of a CLASS
.index Attribute of CLASS corresponds to  FIELD in RECORD
.index CLASS attributes correspond to RECORD FIELDs
represented by an ATTRIBUTE to the CLASS.
.p
Another way of accessing the data base is to use the
SCHEMA directly in the SIMULA program.
.index SCHEMA, access to in a SIMULA applications program
.index Data Base Description, access to in an application
.index General-purpose, data independent application programs
.index Data independent application programs
.index Independent of data application programs
The SCHEMA is in SIMULA represented
by objects of the CLASS RSPEC.
.index RSPEC class containing RECORD specification
.index RECORD specification representation in core
These objects are created from
the external SCHEMA when the data base is opened. There is a
procedure GETRECORDSPEC with a TEXT argument indicating
.index PROCEDURE GETRECORDSPEC for reading record specification
.index GETRECORDSPEC PROCEDURE for reading record specification
the RECORD type name. It returns a reference to an object of the
CLASS RSPEC.
.skip
There is no procedure within SIMDBM to create RSPEC objects dynamically
in a user program. They must be created beforehand by running SPEC.
However, in appendix VI there is a procedure MAKERECORDSPEC
which dynamically creates such an object. The few users who really
need this facility will have to copy it from there.
.p
RSPEC has several attributes. One of them is the TEXT ARRAY ANAMES
.index ANAMES = access to FIELD names
.index FIELD name access in applications program
.index FIELD type access in applications program
.index ATYPES = access to FIELD types



which contains the names of all the FIELDs in the record, and the
INTEGER ARRAY ATYPES which indicates the type of the FIELDs.
.p
If the pre-processor PREP was not used to get an internal
data structure for the RECORDs, then the system will automatically
.index Data independent RECORD core representation
.index RECORD core representation, data independent

create a simple and general purpose structure for RECORDs read from
the data base. Each FIELD is simply put into an element of a TEXT ARRAY
parallel to the two ARRAYs ANAMES and ATYPES in the RECORD specification.
.p
This makes it rather simple to write a program which manipulates an
arbitrary data base. An example of such a program is given in
appendix IV, while an example of a program dependent on a known
fixed SUB
.index SUBSCHEMA
.index SUB-SCHEMA

-SCHEMA is shown in appendix II.
.p
A fuller description of the central CLASSes representing RECORDs and
RECORD specifications is given in appendix V.
.no subtitle
.p -5,2,15
3.#HANDLING THE DATA BASE FROM AN APPLICATIONS PROGRAM
.subtitle 3.
.index Data base handling from an applications program
.index Applications program data base handling procedures
.no subtitle
.p -5,2,15
3.1 PROCEDURES FOR DATA MANIPULATION
.subtitle 3.1 PROCEDURES FOR DATA MANIPULATION
.p 0,2,5
The following procedures can be regarded as a Data Manipulation
Language (DML) for SIMULA. The same set of procedures should
.index DML = Data Manipulation Language
.index Data Manipulation Language = DML
be usable against a commercial DBMS system.
.no subtitle
.p -5,2,15
3.1.1 ACCESS TO RECORDS OR SPECIFICATIONS
.subtitle 3.1.1 ACCESS TO RECORDS OR SPECIFICATIONS
.p 0,2,9
REF (RECORD) PROCEDURE GET(KEY,TYPE); TEXT KEY,TYPE;
.index Reading RECORDs from the data base
.index Inputting RECORDs from the data base
.index Getting RECORDs from the data base
.index REF (RECORD) PROCEDURE GET record from the data base
.index GET PROCEDURE record from the data base
.p 0,2,5
This procedure returns a reference to a RECORD object. KEY
is the value of that FIELD in the RECORD, which in the RECORD
specification is marked as an identifying KEY for this RECORD.
There must only be one RECORD with each KEY value.
.p 0,2,5
If there is no natural FIELD to be used as a KEY,
then a unique number can be used as a KEY. The procedure
NEXT__KEY can be used to generate such a unique number.
.p 0,2,5
If the data base did not contain any RECORD with the
given KEY, then GET will return the value NONE.
.p 0,2,8
REF (RSPEC) PROCEDURE GETRECORDSPEC(TYPE); TEXT TYPE;
.index Reading record specifications from the data base
.index Inputting record specifications from the data base
.index Getting record specifications from the data base
.index RECORD specifications reading from the data base
.index REF (RSPEC) PROCEDURE GETRECORDSPEC
.index GETRECORDSPEC PROCEDURE Record specification reading
.index Access to the SCHEMA from an applications program
.p 0,2,5
This procedure returns a reference to an object
of the CLASS RSPEC. This object describes the RECORD TYPE
with the given name. RSPEC is described in more detail in appendix V.
NONE is returned if there is no such RECORD TYPE in the data base.
.p 0,2,8
REF (SETSPEC) PROCEDURE GETSETSPEC(SETTYPE); TEXT SETTYPE;
.index Reading SET specifications from the data base
.index Inputting SET specifications from the data base
.index Getting SET specifications from the data base
.index REF (SETSPEC) PROCEDURE GETSETSPEC
.index GETSETSPEC PROCEDURE SET specification reading
.p 0,2,4
Similar to GETRECORDSPEC, but returns a SETSPEC-object,
that is an object describing a SET. The CLASS SETSPEC is also
described in appendix V.
.p 0,2,9
REF (RECORD) PROCEDURE GETOWNER(R, SET);
.index Reading OWNER given MEMBER
.index Inputting OWNER given MEMBER
.index Getting OWNER given MEMBER
.index REF (RECORD) PROCEDURE GETOWNER SET OWNER reading
.index GETOWNER PROCEDURE SET OWNER reading
.break
REF (RECORD) R; TEXT SET;
.p 0,2,5
If the RECORD R is a MEMBER of a set of the type SET, then
GETOWNER returns a reference
to the OWNER of the set. NONE is returned if R is not a member
of any such set.

.skip
.p -5,2,15
3.1.2 STORAGE OF RECORDS AND INCLUSION IN SETS
.index Writing RECORDS into the data base
.index Outputting RECORDS into the data base
.index Storing RECORDS into the data base
.subtitle 3.1.2 STORE OF RECORDS AND INCLUSION IN SETS
.p 0,2,8
PROCEDURE STORE;
.index PROCEDURE STORE for storing RECORD in the data base
.index STORE PROCEDURE for storing RECORD in the data base
.p 0,2,4
STORE is a procedure attribute to the CLASS RECORD. If
you want to store a RECORD, to which R refers, then you
thus write "R.STORE".
.p 0,2,8
PROCEDURE INSERT(SET,OWNER,MEMBER); TEXT SET;
.index PROCEDURE INSERT for insertion of RECORD into a SET
.index INSERT PROCEDURE for insertion of RECORD into a SET
.break
REF (RECORD) OWNER,MEMBER;
.p 0,2,4
This procedure adds MEMBER as a new MEMBER to the SET which
is owned by OWNER.
.no subtitle
.p -5,2,15
3.1.3 DELETION OF DATA
.subtitle 3.1.3 DELETION OF DATA
.p 0,2,8
PROCEDURE DELETE(R); REF (RECORD) R;
.index PROCEDURE DELETE of a RECORD from the data base
.index DELETE PROCEDURE for deletion of a RECORD
.p 0,2,4
.SKIP
     The RECORD R is removed from the data base and taken
     out of all SETs, to which it may belong.
.SKIP
.p 0,2,8
PROCEDURE REMOVE(SET,MEMBER);
.index PROCEDURE REMOVE for removal of a RECORD from a SET
.index REMOVE PROCEDURE for removal of a RECORD from a SET
.break
TEXT SET; REF (RECORD) MEMBER;
.p 0,2,4
The RECORD "MEMBER" is assumed to be a MEMBER of the SET of
type "SET". The RECORD is removed
from that SET, but is kept in the data base and in any other SETs,
where it may be a MEMBER.
.no subtitle
.p -5,2,15
3.1.4 PROCEDURES FOR ITERATION
.subtitle 3.1.4 PROCEDURES FOR ITERATION
.p 0,2,5
Other CODASYL implementations usually do not have procedures
.index CODASYL Task Group proposal
of this kind, and they are not part of the CODASYL specification.
.index CODASYL Task Group proposal
They are however very useful for SIMULA programmers.
.p 0,2,9
PROCEDURE DOFOREACH(TYPE,ACTION);
.index Search of all RECORDs of given TYPE
.index Scanning of all RECORDs of given TYPE
.index Iteration across all RECORDs of given TYPE
.index PROCEDURE DOFOREACH scan RECORDS of given TYPE
.index DOFOREACH PROCEDURE scan all RECORDS of given type
.break
TEXT TYPE; PROCEDURE ACTION;
.p 0,2,5
All RECORDs of type TYPE are scanned, and for each RECORD the procedure
ACTION is called. ACTION should have one parameter, a reference
to the RECORD. DOFOREACH will call ACTION once for each RECORD.
The programmer can let DOFOREACH do any kind of treatment of the
RECORD. The applications programmer can write ACTION himself,
or use one of several utility procedures within the system.
.SKIP
 The global boolean
     variable BREAK__DO can be set by the procedure ACTION.
     This will cause DOFOREACH to interrupt the scanning.
.SKIP
.p 0,2,9
PROCEDURE MAPSET(OWNER,SET,ACTION);
.index Iteration across set members
.index Search of all SET members
.index Scanning of all SET members
.index PROCEDURE MAPSET apply procedure to RECORDS in given SET
.index MAPSET PROCEDURE scan all RECORDS in given SET
.break
REF (LRECORD) OWNER; TEXT SET; PROCEDURE ACTION;
.p 0,2,5
This procedure is similar to DOFOREACH. But instead of scanning
all RECORDs of a given TYPE, all RECORDs in a SET owned by OWNER
are scanned.
 If the scanning is to
     be interrupted, then the global boolean variable
     BREAK__MAP can be set within the procedure ACTION.
.SKIP
.no subtitle
.p -5,2,15
3.1.5 OTHER PROCEDURES
.subtitle 3.1.5 OTHER PROCEDURES
.p 0,2,9
PROCEDURE DEFINESET(SET,OWNERTYPE,MEMBERTYPE);
.index PROCEDURE DEFINESET for defining new SET TYPE
.index Defining new SET TYPE from applications program
.index SET, new type of, definition of
.index DEFINESET PROCEDURE for defining new SET TYPE
.break
TEXT SET, OWNERTYPE, MEMBERTYPE;
.p 0,2,5
Anywhere in an applications program, new SETs can be
added to the data base. DEFINESET creates a specification
of a SET TYPE with the OWNER of type OWNERTYPE and
members of type MEMBERTYPE
.skip
Example:
.skip 1
DEFINESET("SET3","OWNER3POST","M1TYPE");
.p 0,1,5
Here, a new SET TYPE called SET3 is
introduced, with OWNERs of type OWNER3POST and MEMBERs
of if the type M1TYPE.
.p 0,2,9
INTEGER PROCEDURE NEXT__KEY;
.index INTEGER PROCEDURE NEXT__KEY
.index NEXT__KEY INTEGER PROCEDURE for unique key generation
.index Unique KEY value generator
.index KEY, unique, generation of
.p 0,2,5
All RECORDs in the system must have a unique identification.
Where there is no data FIELD in the RECORD which can serve
as a unique identification, an extra FIELD must be added
for this purpose. Each time such a RECORD is stored into
the data base, a new unique value is needed for this
KEY. The procedure NEXT__KEY can be used, since it will
give a new INTEGER, which is not yet used in the data base,
every time it is called.
This integer is stored in the first line of the data base file
when it is closed, and fetched again when the data base is
opened again. Thus there might be problems if a run was interrupted
abnormally;. the numbers might fail to be unique. To
decrease the risk for this, the number is increased by 100 every
time the base is opened.
.SKIP
     PROCEDURE DISPLAY__RECORDS;
.SKIP
     This procedure displays for all record types in the
     data base its name, and the names of all the fields.
.SKIP
     PROCEDURE DISP__TYPES;
.SKIP
     There is a global variable currentspec which can be set
     prior to the call to this procedure to point to the
     RSPEC object of the record type to be treated.
     DISPTYPES will then type all the field names and their
     types for that record type.
.SKIP
     PROCEDURE TABULATE(R);  REF (RECORD) R;
.SKIP
     This procedure types field names and their values for
     all the fields of the record R in a standard format.
The global variable NAMEONLY can be set to true if this
procedure is to print just the key of the record R.
.skip
PROCEDURE OPENBASE(LOAD_FILE,IMSIZE);
TEXT LOAD_FILE; INTEGER IMSIZE;
.skip
This procedure is called to open the SIMULA directfile which
constitutes the actual data base. LOAD_FILE is the name of
the file and IMSIZE its image size, which was decided upon when
the data base was initially created by running SPEC.
.skip
PROCEDURE CLOSEBASE;
.skip
When processing is terminated, this procedure must be called
to close the data base properly. Besides closing the file,
it writes some status information in the data base. If the
program is abnormally terminated, the base might be left in
an incomplete state and the results of the latest updates
made in that run may be lost.
.SKIP
.no subtitle
.p -5,2,15
3.2 HOW TO WRITE SPECIFIC, PROBLEM-ORIENTED AND READABLE PROGRAMS
.subtitle 3.2 HOW TO WRITE SPECIFIC, PROBLEM-ORIENTED AND READABLE PROGRAMS
.p 0,2,5
The pre-processor PREP is suitable if you want to create
.index PREP pre-processor producing CLASS declarations
.index pre-processor PREP for CLASS declaration generation
.index CLASS declaration, automatic generation of
.index Generation, automatic, of CLASS declarations
programs for SPECIFIC types of RECORDs in the data base.
PREP reads the SCHEMA in the data base and creates SIMULA
source program CLASS declarations, one CLASS for each RECORD type
to be accessed, with one CLASS attribute for each data FIELD
to be accessed, and with ready-made procedure attributes for getting
and storing RECORDs in the data base including data formatting.
.p 0,2,5
Appendix III shows how these CLASSes can look for the RECORD TYPEs
specified in appendix I. Appendix II is an example of how these CLASSes
can be used to manipulate data.
.p 0,2,5
Note the following differences between corresponding programming
in a COBOL environment, using a CODASYL-type DBMS:
.index CODASYL Task Group proposal
.p 0,2,5
The CURRENT concept does not exist.
.index CURRENT
.break
If you for example write "R:-#GET("K1","TYP1");" then this RECORD
will be kept in core until R is given a new value,
indenpendent of any other GET operations binding other variables
to RECORDs.
.p 0,2,5
GET corresponds to FIND + GET according to the CODASYL proposal.
.index FIND
It corresponds to what the CODASYL proposal calls
"LOCATION MODE IS CALC", that is, the RECORD is found through its KEY.
.index CALC location mode
.index LOCATION MODE IS CALC
.index CODASYL Task Group proposal
.p 0,2,5
MODIFY is not implemented, but can be done as GET + STORE.
.index MODIFY
STORE stores a RECORD even if a previous one was in the data base.
The previous RECORD with the same KEY is overwritten.
However, if the boolean variable WRPROTECT is set TRUE,
then SIMDBM will not overwrite but give an error message.
.p 0,2,5
There is no order to the RECORDs of a given TYPE or
the MEMBERs of a given SET. If you want to scan all RECORDs
of a given TYPE or MEMBERs of a given SET, you must use the
procedures DOFOREACH or MAPSET.
For small applications where sorting
is needed, there is a separate module DBSORT to
be contained in the prefix chain. It has DBMSET as prefix and contains
proce dures and other concepts to handle sorted arrays of records
in core.
.no subtitle
.p -5,2,15
3.3 WRITING GENERAL-PURPOSE, DATA-INDEPENDENT PROGRAMS
.subtitle 3.3 WRITING GENERAL-PURPOSE, DATA-INDEPENDENT PROGRAMS
.p 0,2,5
No preprocessor is used for general-purpose, data-independent
programs. The binding between FIELD name and SIMULA data
.index FIELD name acess to in applications program
.index LOCTEXT procedure for finding FIELD name
.index PROCEDURE LOCTEXT for finding FIELD name
structures is instead done at run time under control
of the program. The procedure GETRECORDSPEC is used to get
the specification of a RECORD, which then can be used to
access its FIELDs.
.p 0,2,5
For example, the program can ask the user conversationally for
FIELD names, and then check in the RECORD specification if this
FIELD exists and if so where to find the value.
.p 0,2,5
The procedure LOCTEXT is useful for this:
.skip
INTEGER PROCEDURE LOCTEXT(T,TA); TEXT T; TEXT ARRAY TA;
.p 0,2,5
LOCTEXT searches the TEXT ARRAY TA for an element
equal to T, and returns the index of the found element.
If no element is found, 0 is returned.
.p 0,2,5
Example: Suppose that we have found a RECORD specification
with the statement 'RS:-#GETRECORDSPEC("RTYP1");'. The user now
wants to find the FIELD names "FIELD1" in a RECORD with the KEY
"POSTKEY1". This can be done with the following sequence of statements:
.p 0,2,9
.nofill
r:-get("POSTKEY1","RTYP1");
IF r == NONE THEN error("Record not found") ELSE
BEGIN
   n:= loctext("FIELD1",RS.ANAMES);
   IF n = 0 THEN error("Field undefined in record !")
   ELSE answer:- r.avalues(n);
   OUTTEXT("FIELD1 = "); outtext(answer); outimage;
END;
.fill
Note that, if records of a particular type are accessed iteratively;
then LOCTEXT need only be called once for each field to be treated.
The values can thereby be saved in integer variables before
the iteration is started. These variables can then be used to index
the array AVALUES during the iteration.
.no subtitle
.p -5,2,15
3.4 COORDINATION OF DATA STRUCTURES IN CORE AND IN THE DATA BASE
.subtitle 3.4 COORDINATION OF DATA STRUCTURES IN CORE AND IN THE DATA BASE
.index CLASS into RECORD mapping
.index RECORD into CLASS mapping
.p 0,2,5
Sometimes you have already existing SIMULA programs and want them
to get certain data from a data base. You want to minimize the necessary
changes in the program. Here is one way of doing this:
.p 0,2,5
For each CLASS in your SIMULA program, in whose objects you want to
store data taken from data base RECORDs, you write a BOOLEAN
procedure with two parameters KEY and OBJ.
.p 0,2,5
KEY contains the value of the key of the RECORD to be read from
the data base. OBJ is a reference to the CLASS object into which
data is to be read from the data base. The procedure gets the
RECORD from the data base and stores the data you want into
certain attributes of the OBJ CLASS object.
.p 0,2,5
The procedure returns TRUE if the RECORD was found in the data base,
otherwise it returns FALSE.
.p 0,2,8
Example:
.p 0,2,5
Suppose that we want to define objects of the CLASS 'CLASS2'
by getting RECORDs of the CLASS 'REPORT' and using the first, third
and fifth FIELD in those RECORDs (of type TEXT, INTEGER resp.#REAL).
These three FIELDs are to be stored into the attributes A1, A2
resp.#A3 which have the corresponding types.
.p 0,2,5
A procedure to do this might look like this:
.p 0,2,13
.nofill
BOOLEAN PROCEDURE LOADCLASS2(key, obj);
TEXT key; REF(class2) obj;
BEGIN
   inspect GET(key, "REPORT") do
   BEGIN loadclass2:= TRUE;
     a1:- r.avalues(1);
     a2:= r.avalues(3).getint;
     a3:= r.avalues(5).getreal;
   END;
END of lodclass2;
.fill
.p 0,2,5
There is a preprocessor PREP2 which automatically generates this
.index pre-processor generating CLASS to RECORD mapper
.index generating procedure for CLASS to RECORD mapping
kind of procedures, using the SCHEMA in the data base to find
the position and type of the FIELDs to be transferred.
.p 0,2,5
Suppose that the three FIELDs are in the data base
called id, felgrad and reptid. The dialogue with the
preprocessor PREP2 to create the procedure above would then
be:
.p 0,2,2
Give procedure,class and record type: LOADCLASS2,CLASS2,REPORT
.break
Give attributes and fields: A1=id,A2=felgrad,A3=reptid
.no subtitle
.p -5,2,15
.nofill
3.5##CONCATENATION OF RECORD TYPES.
.fill
.skip
On retrival (via GET or DOFOREACH) or whenever a record
is interpreted through the procedure LOAD of the class RECORD,
record types can be concatenated. To describe the structure of
a record type, a special class (externally represented
by a system defined record type) RSPEC is used.
Some details of this are given i appendix V.
Concatenated record types are specified by creating
an extra RSPEC object in the following way:
.skip
.nofill
   RNAME   =  name of the new record type
   BASE    =  0  signifies that it is a
                 concatenated record type
   ADIM    =  sum of ADIM for the two concatenated
              types
   KEY     =  RECTYPE1,RECTYPE2[,KEY2]
              where KEY2 is the name of the
              field in RECTYPE1 which identifies
              the corresponding record of
              type RECTYPE2 (need not be specified
              when the same as key for RECTYPE1).
.skip
.fill
When such an RSPEC-record has been stored, SIBDBM will
automatically produce the corresponding concatenated records
(on retrieval only, on updating and storing the parts
must still be treated separately).
Note that the other fields of the RSPEC records are
irrelevant for such record types.
.skip
Observe that this mechanism can be used recursively, so that
the record types beeing concatenated may themselves be
concatenated record types.
.skip
Using this facility data can be partitioned, so that data
describing objects are stored in several record types,
e.g. the most frequently used in one record type, and the rest
in another type under the same key.
.break
Applications needing data from both types can then
be designed using a concatenated record type, but for most
applications it will be sufficient to work on one type only.
.skip
Another application would be to make a joint retrieval
on some record and its owner in some set, provided that the
key of the owner is stored in some field of the members.
This is done by just defining an RSPEC record with key
as follows: (and the other fields as described above)
.SKIP
MEMBERTYPE,OWNERTYPE,KEYFIELD
.skip
where KEYFIELD is the field within MEMBERTYPE where
the key of the unique owner is stored.
.break
All retrieval operations on this new record type will then
deliver data for the member and owner together. The field names
will be prefixed with record name for the owner.
.page
4.#COMPARISON WITH A COMPLETE, COBOL-BASED CODASYL DBMS SYSTEM
.index CODASYL Task Group proposal
.subtitle 4.#COMPARISON WITH A COMPLETE, COBOL-BASED CODASYL DBMS SYSTEM
.p 0,2,5
Concurrently with the development of the system described in this
report, we have been testing the CODASYL-type DBMS system
marketed by DEC for the DECsystem-10.
.index DEC = Digital Equipment Corporation
.index Digital Equipment Corporation
.index Comparison with a CODASYL type DBMS system
.index CODASYL type DBMS system, comparison with SIMDBM
.index COBOL based DBMS, comparison with SIMDBM
.p 0,2,5
We have written a number of COBOL programs to try to asess the
facilities of the system. Some of those programs have been written
both in COBOL, using the DEC DBMS system, and in SIMULA using our
DBMS system.
.p 0,2,5
We have found that SIMULA gives a much more flexible handling of
data bases. However, connecting SIMULA to the DEC DBMS system
would only give some of these flexibility advantages. Other
of the flexibility advantages are peculiar to our way of
implementing the DBMS system.
.p 0,2,5
We therefore think that it might be a better idea to develop our
system further than to try to connect SIMULA to the DEC DBMS system.
.p 0,2,5
Here are the most important differences:
.p -4,2,8
+++ Easier to search in complex structures.
.index Advantages compared to COBOL-based DBMS-es
.p 0,2,5
Using procedures (which in SIMULA always can be used recursively)
it is simple to program such searches. In COBOL, which lacks
this kind of procedure concept, such programs will be rather
difficult to write.
.p 0,2,5
This is also connected with the concept of CURRENCY in COBOL-based
DBMS systems. DBMS, as seen from COBOL, can only see one RECORD
and one SET at a time (current of record, current of set).
In SIMULA, reference variables can in a natural way be used
to refer to any number of RECORDs. These RECORDs can be accessible
at the same time, even though no fixed core space has to be allocated
for them. COBOL lacks reference variables.
.p -4,2,8
+++ Letting the user program add new structures to the data base.
.p 0,2,5
In our system, an applications program can extend the SCHEMA with
both new RECORD TYPEs and new SET TYPEs. A#complex execution can
thus create data with a complex structure, which directly can be
stored in the data base, even if the structures are not already
foreseen in the SCHEMA. It is also simple to create temporary
SETs of RECORDs to which fast access is needed at a certain time.
.skip
To create new sets the procedure DEFINESET (described in chapter 3) can
be used. To create new record specifications within user programs
is not considered to be a very common operation. Usually the program
SPEC can be used separately to do this. However, it is not very difficult
to do it, given the structure of record specifications in appendix V.
No procedure for this is included in SIMDBM, but if wanted the procedure
MAKERECORDSPEC can be copied manually from appendix VI, which also
contains an example of how it is called.
.p -4,2,8
+++ Procedures for iteration.
.p 0,2,5
Procedures like DOFOREACH and MAPSET are very natural in a programming
language containing the procedure concept. A similar mechanism
could be added to COBOL-DML, but it would be much more awkward to use.
.p -4,2,8
+++ Access to the SCHEMA in applications programs.
.p 0,2,5
Access to the SCHEMA is important if you want to write general-purpose
programs, not bound to a given SCHEMA. From the CODASYL
.index CODASYL Task Group proposal
proposal, one gets the impression that writing such general-purpose programs
are forbidden for security reasons.
However, we feel that at least some programmers ought to have this
right. It would not be difficult, if desired, to make access to
the SCHEMA a privilegied operation.
.nofill
.no subtitle
.page
APPENDIX I
.skip
An example of a dialogue to create a data description.
=====================================================
.skip
.SKIP
     Give name of data base file: ex.tmp
     image size:68
     Delimiters /92,93/:
     System area sizes /20,10,10,10,10,10,10/:
     *NAME,PERSON
     *TEXT,identity,sex
     *INTEGER,birthyear
     *TEXT,adress
     *INTEGER,weight,height
     *KEY,identity
     *RECORD
     Record OK, Give ne specification or EX to finish.
     *NAME,CAR
     *TEXT,regno,make,colour
     *INTEGER,miles
     *KEY,regno
     *SIZE,20
     *RECORD
     Record OK, Give ne specification or EX to finish.
     *NAME,COMPANY
     *TEXT,identity,products,adress
     *INTEGER,numberofemp
     *KEY,identity
     *SIZE,20
     *RECORD
     Record OK, Give ne specification or EX to finish.
     *NAME,CITY
     *TEXT,identity
     *INTEGER,inhabitants
     *TEXT,region
     *KEY,identity
     *SIZE,5
     *RECORD
     Record OK, Give ne specification or EX to finish.
     *EXIT
.skip 2
In this dialogue four record types are defined:
.break
person,car,company and city.
.fill
Internal SIMULA representations for three of these are found in
Appendix III.
.page
.nofill
APPENDIX II
.skip
An example of a specific SIMULA program using
.break
=============================================
a data base.
.break
===========
.fill
.skip
This program works on a data base containing the records specified
in Appendix I, and they are supposed to be connected via sets
in the following way:
.skip
CITY-------->COMPANY--------->PERSON----------->CAR
#####hascomp#########employs#########hascar
.skip
The program counts, for all companies with more than 200 employees,
the number of employees who own a car. For each of those companies
its name, the name of the city where it is located, the total
number of employees and the number of car owners is printed.
.skip
The prefix owndat can easily be generated using the preprocessor
PREP, and the code thus generated is presented in appendix III.
The prefix chain to the class owndat contains the entire
SIMDBM system.
.nofill
.skip 2
BEGIN
.skip
  ...  various external declarations  ...
.skip
  owndat("","",true) begin
.SKIP
    PROCEDURE empcount(r); REF(company) r;
    BEGIN REF (city) c; INTEGER ncars;
.SKIP
      PROCEDURE carcount(p); REF (person) p;
      PROCEDURE break(r); ref (record) r;
      breakmap:=true;
      mapset(p,"hascar",break);
        IF breakmap THEN ncars:=ncars+1;
      END;
.SKIP
      IF r.numberofemp _> 200 THEN
      BEGIN
        mapset(r,"employs",carcount);
        c:-getowner(r,Copy("hascomp"));
        _! output result;
        Outtext("Company = ");
        Outtext(r.identity); Outimage;
        Outtext("City    = ");
        Outtext(c.identity); Outimage;
        Outtext("Total nr of employees = ");
        Outint(r.numberofemp,5);
        Outimage;
        Outtext("Nr of car owners      = ");
        Outint(ncars,5); Outimage;
      END;
    END of empcount;
.SKIP
    _! main program  ---------------;
.SKIP
    doforeach("company",empcount);
  END;
END;
.page
APPENDIX III
.skip
Examples of SIMULA classes which can be generated
.break
=================================================
automatically from the stored data description.
.break
==============================================
.fill
.skip
     Suppose we want to have internal representations for
     the records PERSON, COMPANY and CITY as specified in
     appendix I. We want these classes to be embedded in
     the class OWNDAT.SIM which is to be used as prefix to
     some application programs.
.SKIP
     Such a class can be produced by the program PREP via
     the following dialogue:
.nofill
.SKIP
     Name of data base file: EX.TMP
     Image size: 68
     Name of output file (without extension): OWNDAT
     Records to expand: PERSON,COMPANY,CITY
     Linked records? NO
.fill
.SKIP
     The question Linked records is answered by YES only if
     the records are connected by sets.  In that case the
     class DBMSET for set handling will be taken as prefix
     to OWNDAT instead of SIMDBM. (This will actually
     be needed if this class is to be used as prefix
     to the user program in appendix II.)

.SKIP
     Provided the data base was specified as in appendix I,
     the file OWNDAT.SIM will now contain the following
     code:
.nofill
.SKIP
     OPTIONS(/external);
     EXTERNAL REF (Infile) PROCEDURE findinfile;
     EXTERNAL REF (Outfile) PROCEDURE findoutfile;
     EXTERNAL TEXT PROCEDURE conc,front,scanto,upcase,
     frontstrip,rest,checkextension,getitem;
     EXTERNAL CHARACTER PROCEDURE fetchar,findtrigger;
     EXTERNAL LONG REAL PROCEDURE scanreal;
     EXTERNAL PROCEDURE split;
     EXTERNAL INTEGER PROCEDURE
     checkreal,checkint,scanint,ilog,
     maxint,search,splita;
     EXTERNAL BOOLEAN PROCEDURE menu,puttext;
     EXTERNAL CLASS safeio,simdbm;
     simdbm CLASS owndat;
     BEGIN
       TEXT ARRAY noargs[1:1],splitarr[1:200];
       TEXT b__,t__;
       INTEGER i__,k__;
       REF (rspec) r;
.SKIP
       record CLASS person(identity,sex,birthyear,
       adress,weight,height);
       INTEGER birthyear,weight,height;
       TEXT identity,sex,adress;
       BEGIN
         TEXT PROCEDURE getkey; getkey:-identity;
         PROCEDURE store; inspect d__file do
         BEGIN TEXT s;
           dbskey:=lookup(identity,"PERSON");
           Locate(dbskey);
           s:-conc(identity,b__,sex,b__,
           intput(birthyear),b__,
           adress,b__,intput(weight),b__,intput(height));
           storerecord(THIS Directfile,
           conc(Copy("  "),syn__),s);
         END of store;
         REF (person) PROCEDURE load(t);
         VALUE t; TEXT t;
         BEGIN REF (person) r;
           TEXT ARRAY avalues[1:spec.adim];
           r:-NEW person(spec,avalues,
           NOTEXT,NOTEXT,0,NOTEXT,0,0);
           splita(t,b__,avalues,spec.adim);
           r.identity:-avalues(1);
           r.sex:-avalues(2);
           r.birthyear:=avalues(3).Getint;
           r.adress:-avalues(4);
           r.weight:=avalues(5).Getint;
           r.height:=avalues(6).Getint;
           load:-r;
         END of load;
       END of PERSON;
.SKIP
.SKIP
       record CLASS
       company(identity,products,adress,numberofemp);
       INTEGER numberofemp;
       TEXT identity,products,adress;
       BEGIN
         TEXT PROCEDURE getkey; getkey:-identity;
         PROCEDURE store; INSPECT d__file DO
         BEGIN TEXT s;
           dbskey:=lookup(identity,"COMPANY");
           Locate(dbskey);
           s:-conc(identity,b__,products,b__,adress,b__,
           intput(numberofemp));
           storerecord(THIS Directfile,conc(Copy("  "),
           syn__),s);
         END of store;
         REF (company) PROCEDURE load(t);
         VALUE t; TEXT t;
         BEGIN REF (company) r;
           TEXT ARRAY avalues[1:spec.adim];
           r:-NEW company(spec,avalues,NOTEXT,NOTEXT,
           NOTEXT,0);
           splita(t,b__,avalues,spec.adim);
           r.identity:-avalues(1);
           r.products:-avalues(2);
           r.adress:-avalues(3);
           r.numberofemp:=avalues(4).Getint;
           load:-r;
         END of load;
.SKIP
       END of COMPANY;
.SKIP
.SKIP
       record CLASS city(identity,inhabitants,region);
       INTEGER inhabitants;
       TEXT identity,region;
       BEGIN
         TEXT PROCEDURE getkey; getkey:-identity;
         PROCEDURE store; INSPECT d__file DO
         BEGIN TEXT s;
           dbskey:=lookup(identity,"CITY");
           Locate(dbskey);
           s:-conc(identity,b__,intput(inhabitants),
           b__,region);
           storerecord(THIS Directfile,conc(Copy("  "),
           syn__),s);
         END of store;
         REF (city) PROCEDURE load(t); VALUE t; TEXT t;
         BEGIN REF (city) r;
           TEXT ARRAY avalues[1:spec.adim];
           r:-NEW city(spec,avalues,NOTEXT,0,NOTEXT);
           splita(t,b__,avalues,spec.adim);
           r.identity:-avalues(1);
           r.inhabitants:=avalues(2).Getint;
           r.region:-avalues(3);
           load:-r;
         END of load;
       END of CITY;
.SKIP
       b__:-backslash;
       r:-getrecordspec("PERSON");
       r.prototype:-NEW person(r,noargs,NOTEXT,
       NOTEXT,0,NOTEXT,0,0);
       r:-getrecordspec("COMPANY");
       r.prototype:-NEW company(r,noargs,NOTEXT,
       NOTEXT,NOTEXT,0);
       r:-getrecordspec("CITY");
       r.prototype:-NEW city(r,noargs,NOTEXT,0,NOTEXT);
       INNER;
     END;
.PAGE
.SKIP
.fill
     APPENDIX IV
.SKIP
     Example of a general program which can be used
     ==============================================
.break
     on any data base.
.break
     ================
.SKIP
     This program computes the mean value of any numeric
     field over all fields of a particular record type.  The
     names of the record type and the field are to be given
     on the user terminal.
.SKIP
.nofill
     BEGIN
       EXTERNAL TEXT PROCEDURE conc,front,scanto,
       upcase,frontstrip,rest,getitem;
       EXTERNAL LONG REAL PROCEDURE scanreal;
       EXTERNAL PROCEDURE split;
       EXTERNAL INTEGER PROCEDURE checkreal,checkint,
       scanint,maxint,search,splita;
       EXTERNAL CLASS dbmmin;
       dbmmin("aa.bas",68,TRUE) BEGIN
         TEXT type,field; INTEGER fieldpos,count;
         REAL sum; REF(rspec)spec;
.SKIP
         PROCEDURE add(r); REF(record)r;
         BEGIN count:=count+1;
           sum:=sum+r.avalues(fieldpos).Getreal;
         END of add;
.SKIP
         BOOLEAN PROCEDURE checktype;
         BEGIN spec:-getrecordspec(type);
         checktype:=spec=/=NONE; END;
.SKIP
         BOOLEAN PROCEDURE checkfield;
         BEGIN
           fieldpos:=loctext(field,spec.anames);
           IF fieldpos_>0 THEN
           checkfield:=spec.atypes(fieldpos)_<3;
         END of checkfield;
.SKIP
         request("Give record type: ",""
         ,type,checktype,
         "There is no such type",notext);
.SKIP
         request("Give field name: ","",
         field,checkfield,
         "No such numeric field",notext);
.SKIP
         count:=sum:=0;
         doforeach(type,add);
         IF count_>0 THEN sum:=sum//count;
         Outtext("Mean value is = ");
         Outreal(sum,5,15); outimage;
       END;
     END;
.PAGE
.SKIP
APPENDIX V
.SKIP
Description of classes for internal representation
==================================================
of records and record specifications.
====================================
.SKIP
.fill
     The essential stucture of these classes is shown, and
     each attribute is declared but only those which are of
     interest to an external user are further explained.
     The procedure attributes are indicated but the code is
     omitted.
.SKIP
.nofill
       CLASS record(spec,avalues);
       REF (rspec) spec; TEXT ARRAY avalues;
       _!
       spec         pointer to rspec object with
                    specification for this record type
       avalues      text array with attribute values
       ;
       VIRTUAL: TEXT PROCEDURE getkey;
       REF (record) PROCEDURE load;
       PROCEDURE store;
       BEGIN  INTEGER dbskey,type__;
         TEXT syn__;
         TEXT PROCEDURE getkey;
         getkey:-avalues(spec.keypos);
         REF (record) PROCEDURE load(t); TEXT t;
         begin  ....  end;
         PROCEDURE store;
         begin  ...  end;
         ...
       END of record;
.SKIP
       Record CLASS rspec(rname,
       key,base,size,keypos,adim,anames,atypes);
       TEXT rname,key;
       INTEGER base,size,keypos,adim;
       TEXT ARRAY anames; INTEGER ARRAY atypes;
       _!
       rname     name of record
       key       key attribute
       base      start location for primary data area
       size      size of primary data area
       keypos    position of key among parameters
       adim      number of attributes
       anames    text array containing all
                 attribute names
       atypes    integer array with types:
                 1=integer, 2=real, 3=text
                 4=integer array, 5=real array
                 6=text array
       ;
       BEGIN
         REF (record) prototype;
         REF (rspec) PROCEDURE load(t); TEXT t;
         begin  ...  end;
         ...
       END of rspec;
.SKIP
.SKIP
       CLASS setspec(setname,ownertype,membertype);
       TEXT setname,ownertype,membertype;
       _!
       setname     name of set
       ownertype   record type of owner
       membertype allowed type for the members
       ;
       BEGIN
         ...
       END of setspec;
.PAGE
.SKIP
APPENDIX VI
.SKIP
Description of the main classes of the system.
=============================================
.fill
.skip
     The SIMDBM system is partitioned into two separate
     modules which are classes in a prefix chain.  The
     innermost of these classes has as prefix SAFEIO, which
     is a package for safe terminal input also written in
     SIMULA.  SAFEIO is documented elsewhere.
.SKIP
     On the DEC 10 SIMULA system the two modules are
     separately compiled classes.
.SKIP
     SIMDBM contains the class definitions outlined in
     appendix V and most of the procedures mentioned in
     section 3.1 and several other procedures used
     internally.
.SKIP
     DBMSET contains the facilities needed to manipulate
     SETs in the data base.  Therefore this module can be
     excluded for applications where SETs are not used.
.skip
In addition to this there are two modules containing facilities which
are not so frequently used:
.skip
DBSORT
.skip
contains procedures for creating and processing sorted
arrays of record objects. This can sometimes be useful, sinc
the SET concept in SIMDBM is unordered.
.skip
SPECIF
.skip
This module contains a procedure MAKERECORDSPEC, which can be
used in applications where a user program is to create new
record types dynamically. Then this procedure can be copied
from the module SPECIF.SIM, which is a main program containing
MAKERECORDSPEC and a test example showing how it is used.
.skip
The users that need this facility could just copy the procedure
into their program and use it according to the example below:
.skip
.nofill
BEGIN
  EXTERNAL REF (Infile) PROCEDURE findinfile;
  EXTERNAL REF (Directfile) PROCEDURE finddirectfile;
  EXTERNAL REF (Outfile) PROCEDURE findoutfile;
  EXTERNAL TEXT PROCEDURE front,scanto,getitem;
  EXTERNAL INTEGER PROCEDURE maxint,search,splita;
  EXTERNAL PROCEDURE split;
  EXTERNAL BOOLEAN PROCEDURE puttext;
  EXTERNAL TEXT PROCEDURE conc,upcase,frontstrip,
  rest,checkextension;
  EXTERNAL CHARACTER PROCEDURE fetchar,findtrigger;
  EXTERNAL LONG REAL PROCEDURE scanreal;
  EXTERNAL INTEGER PROCEDURE checkreal,checkint,
  scanint,ilog;
  EXTERNAL BOOLEAN PROCEDURE menu;
  EXTERNAL CLASS safeio,simdbm;
  simdbm("","",TRUE) BEGIN
    INTEGER k; TEXT ARRAY ta[1:4];
    REF (record) r1; REF (rspec) rs;
.skip
    REF (rspec) PROCEDURE makerecordspec(rname,
    fnames,ftypes,rkey,rsize,nfields);
    VALUE rname,fnames,ftypes,rkey;
    TEXT rname,fnames,ftypes,rkey;
    INTEGER rsize,nfields;
    BEGIN
      INTEGER k,n,keypos;
      INTEGER ARRAY ia[1:nfields+1];
      TEXT ARRAY ta[1:nfields+1],rta[1:8];
      REF (rspec) rs;
.skip
      PROCEDURE splitt(t); TEXT t;
      BEGIN
        k:=splita(t,komma,ta,nfields);
.break
        IF k < nfields THEN
        BEGIN
           outline("ILLEGAL ARG TO MAKERECORDSPEC!");
           GOTO fin; END;
      END SPLITT;
.skip
      splitt(ftypes);
      FOR k:=1 STEP 1 UNTIL nfields DO
      ia(k):=scanint(ta(k));
      splitt(fnames);
      keypos:=loctext(rkey,ta);
      rta(1):-rname; rta(2):-rkey;
      rta(3):-intput(oflowtop);
      rta(4):-intput(rsize); rta(5):-intput(keypos);
      rta(6):-intput(nfields);
      rta(7):-fnames; rta(8):-ftypes;
      rs:-NEW rspec(spec__spec,rta,rname,rkey,oflowtop,
      rsize,keypos,nfields,ta,ia);
      oflowtop:=oflowtop+rsize;
      rs.store;
      rs.prototype:-new record(rs,ta);
      makerecordspec:-rs;
      fin:
    END MAKERECORDSPEC;
.skip
    !  ------------  START OF MAIN  ----------------;
.skip
    ! create specification for new record type RNEW;
.skip
    rs:-makerecordspec("RNEW","X,Y,Z",
    "3,1,3","X",20,3);
.skip
    ! Example of use of RNEW:
    ! generate and store 10 instances of
      record type RNEW;
.skip
    IF rs =/= NONE THEN
    BEGIN
      FOR k:=1 STEP 1 UNTIL 10 DO
      BEGIN
        ta(1):-intput(100+k); ta(2):-intput(100-k);
        ta(3):-intput(k);
        r1:-NEW record(rs,ta); r1.store;
      END;
    END;
    eof:
  END;
END;
.SKIP
.page
APPENDIX VII
.skip
.nofill
How to use several data bases simultaneously.
============================================
.skip
.fill
The basic system SIMDBM does not allow more than one
data base at a time to be treated. However, by using
the class BASESPEC listed below one can save the variables
inside SIMDBM which specify what is unique to a particular
data base file. Such a class object can be created by
calling the procedure SAVEBASE, and a data base is
reactivated for processing by calling its procedure attribute
SETBASE.
.skip
The rest, we hope, will be obvious from the example
of use given below.
.skip 2
.nofill
BEGIN
  EXTERNAL REF (Infile) PROCEDURE findinfile;
  EXTERNAL REF (Directfile) PROCEDURE finddirectfile;
  EXTERNAL REF (Outfile) PROCEDURE findoutfile;
  EXTERNAL TEXT PROCEDURE front,scanto,getitem;
  EXTERNAL INTEGER PROCEDURE maxint,search,splita;
  EXTERNAL PROCEDURE split;
  EXTERNAL BOOLEAN PROCEDURE puttext;
  EXTERNAL TEXT PROCEDURE conc,upcase,frontstrip,
  rest,checkextension;
  EXTERNAL CHARACTER PROCEDURE fetchar,findtrigger;
  EXTERNAL LONG REAL PROCEDURE scanreal;
  EXTERNAL INTEGER PROCEDURE checkreal,checkint,
  scanint,ilog;
  EXTERNAL BOOLEAN PROCEDURE menu;
  EXTERNAL CLASS safeio,simdbm;
  simdbm("","","",68,TRUE) BEGIN
    INTEGER k,n; TEXT t; TEXT ARRAY ta[1:4];
    REF (rspec) rs,rs2;
    REF (basespec) dokbas,keybas;
    REF (basespec) prevbase;

    CLASS basespec(df,rl,top,gk,bs,bsc,arrc,
    stbuff,rslist);
    ! for set handling: one more parameter:
      ref (setspec) sslist;
    REF (Directfile) df; INTEGER rl,top,gk;
    REF (rspec) rslist;
    TEXT bs,arrc,stbuff; CHARACTER bsc;
    BEGIN
      PROCEDURE setbase;
      BEGIN
        ! save again those variables which might
        have been changed for the previous base;
        INSPECT prevbase DO
        BEGIN top:=oflowtop; gk:=gen_key; END;
        ! for applications adding record and
          set specifications, RECORDSPEC and STAB
          should also be saved again;
        prevbase:-THIS basespec;
        d__file:-df; rlength:=rl; oflowtop:=top;
        gen_key:=gk; backslash:-bs; cback:=bsc;
        arrchar:-arrc; store_buff:-stbuff;
        recordspec:-rslist;
        ! for applications with set handling: stab:-sslist;
      END setbase;
    END basespec;

    REF (basespec) PROCEDURE savebase;
    savebase:-NEW basespec(d__file,rlength,oflowtop,gen_key,
    backslash,cback,arrchar,store_buff,recordspec);
    ! for set handling, one more parameter: stab;


    !  ------------  START OF MAIN  ----------------;

    ! example of two bases used in paralell by means of
      the class BASESPEC and the procedure SAVEBASE;

    ! open bases and set pointers to their definitions;
    openbase("padok.bas",238); dokbas:-savebase;
    openbase("padkey.bas",78); keybas:-savebase;

    ! actualize base of documents, read one document;
    dokbas.setbase;
    tabulate(get("19645","DOKUMENT"));
    ! actualize base of keywords and
      read one keyword record;
    keybas.setbase;
    tabulate(get("BOK","KEYWORD"));
    closebase;
    dokbas.setbase; closebase;

    eof:
  END;
END;
.PAGE
.no subtitle
.page
.p -5,3,40
Appendix VII: INDEX
.subtitle Appendix VII: INDEX
.p 0,2,5
.print index