Multics Technical Bulletin                       MTB-545, Rev. 01
  DM: Relation Manager Functional Spec

  To:       Distribution

  From:     Lindsey Spratt and Lee Baldwin

  Date:     05/31/84

  Subject:  Data Management: Relation Manager Functional Specification

  1 ABSTRACT

       The  interface to  the relation  manager is  described, with
  some discussion of  how the interface is to be  used and what the
  major implications of the interface are.

       The  first  revision  includes  the  addition  of  new entry |
  points,  and a  general reorganization of  the documentation.  An |
  updated description of the  specification structures can be found |
  in Appendix A, and the  information structures used are described |
  in  Appendix   B.   The  entry   points  are  now   presented  in |
  alphabetical order.                                               |

  Comments should be sent to the author:

  via Multics Mail:
     Spratt.Multics on either MIT Multics or System M.

  via US Mail:
     Lindsey Spratt
     Honeywell Information Systems, inc.
     4 Cambridge Center
     Cambridge, Massachusetts 02142

  via telephone:
     (HVN) 261-9321, or
     (617) 492-9321

  _________________________________________________________________

  Multics  project  internal  working  documentation.   Not  to  be
  reproduced or distributed outside the Multics project without the
  consent of the author or the author's management.



                            CONTENTS

                                                         Page

                 1 Abstract . . . . . . . . . . . . . .     i
                 2 Introduction . . . . . . . . . . . .     1
                 3 Significant Changes Contained in
                  Revision 1  . . . . . . . . . . . . .     1
                 4 Description of the Operations  . . .     2
                    relation_manager_ . . . . . . . . .     3
                       Data management data types . . .     3
                       $close . . . . . . . . . . . . .     4
                       $create_cursor . . . . . . . . .     5
                       $create_index  . . . . . . . . .     6
                       $create_relation . . . . . . . .     8
                       $create_subset_index
                        (unimplemented) . . . . . . . .    10
                       $delete_tuple_by_id  . . . . . .    11
                       $delete_tuples_by_id . . . . . .    12
                       $delete_tuples_by_spec . . . . .    13
                       $destroy_cursor  . . . . . . . .    14
                       $destroy_index . . . . . . . . .    15
                       $destroy_relation_by_opening . .    16
                       $destroy_relation_by_path  . . .    17
                       $get_count . . . . . . . . . . .    18
                       $get_cursor_area_ptr . . . . . .    19
                       $get_cursor_opening_id . . . . .    20
                       $get_description . . . . . . . .    21
                       $get_duplicate_key_count . . . .    22
                       $get_index_id  . . . . . . . . .    23
                       $get_max_and_min_attributes
                        (unimplemented) . . . . . . . .    24
                       $get_population  . . . . . . . .    25
                       $get_record_collection_id  . . .    26
                       $get_tuple_by_id . . . . . . . .    27
                       $get_tuple_id  . . . . . . . . .    29
                       $get_tuples_and_ids  . . . . . .    31
                       $get_tuple_array_and_ids . . . .    33
                       $get_tuple_array_by_id . . . . .    35
                       $get_tuple_array_by_spec . . . .    36
                       $get_tuples_by_id  . . . . . . .    37
                       $get_tuples_by_spec  . . . . . .    39
                       $modify_tuple_by_id  . . . . . .    41
                       $modify_tuples_by_id . . . . . .    42



                         CONTENTS (cont)

                                                         Page

                       $modify_tuples_by_spec
                        (unimplemented) . . . . . . . .    44
                       $open  . . . . . . . . . . . . .    46
                       $put_tuple . . . . . . . . . . .    47
                       $put_tuples  . . . . . . . . . .    48
                       $set_scope . . . . . . . . . . .    50
                 Appendix A - Specification Structures     52
                    The specification_head structure  .    52
                    The subset_specification structure     52
                    The relation_search_specification
                     structure  . . . . . . . . . . . .    53
                    The relation_numeric_specification
                     structure  . . . . . . . . . . . .    56
                 Appendix B - Information Structures  .    58
                    The element_id_list structure . . .    58
                    The file_create_info structure  . .    58
                    The id_list structure . . . . . . .    59
                    The rel_creation_info structure . .    60
                    The relation_description structure     60
                    The relation_index_flags structure     62
                    The typed_vector structure  . . . .    63
                    The typed_vector_array structure  .    64
                    The typed_vector_list structure . .    65

  Multics Technical Bulletin                       MTB-545, Rev. 01
  DM: Relation Manager Functional Spec

  2 INTRODUCTION

       The relation manager supports the organization of a relation
  and multiple indices.   The tuples of the relation  are stored as
  records in  a record collection,  managed by the  record manager.
  Since there is one relation per file, the name of the relation is
  the name of  the file in which it resides.   At some point in the
  future  this  restriction  may  be  loosened  and  the  number of
  relations  in a  file may  be increased.   An extension  would be
  necessary  to the  interface which  allows distinguishing between
  different  relations  in the  same  file.  If  this is  done, the
  situation of interest is to have tuples (or records) of different
  format  (from different  relations and  therefore probably having
  different attributes) in the  same record collection.  This would
  provide  the ability  of placing  related records  from different
  relations in  the same control interval.   This, in turn, reduces
  reads from  disk (of control  intervals, the unit  of disk reads)
  for certain patterns of reference of the database.

       The separate indices are  implemented as physically distinct
  indices in the file of the relation.  Initially, the only kind of
  indexing available  will be the multi-field  sorting index with a
  fixed format key and multiple data  types.  The keys in any index
  of the relation are constructed such that:

     1) The indexed  fields of the key  correspond to attributes of
        the relation;
     2) No two fields in a key  correspond to the same attribute of
        the relation;
     3) The key  contains one field which  is the record identifier
        of the tuple  from which the data in  the indexed fields of
        the key was extracted.

  The relation  manager guarantees that the  tuples and the indices
  do  not  become  inconsistent,  that  is  that  the  above  three
  conditions are always true.

       There  is only  one kind of  opening which is  used with the
  relation manager, the  file opening.  The file opening  is of the
  file which contains the relation.  This assumes that there is one
  relation per file.  Changing to support multiple relations is not
  a major perturbation, in terms of openings, as the argument which
  is  now  filled with  a  file opening  id  can be  filled  with a
  relation opening id.

  3 SIGNIFICANT CHANGES CONTAINED IN REVISION 1                     |

       The following entry points are new:                          |


  MTB-545, Rev. 01                       Multics Technical Bulletin
                               DM: Relation Manager Functional Spec

|      $get_cursor_area_ptr
|      $get_cursor_opening_id
|      $get_index__id
|      $get_record_collection_id
|      $get_tuple_array_and_ids
|      $get_tuple_array_by_id
|      $get_tuple_array_by_spec

|      The  entry  points  which  are  currently  unimplemented are
| indicated as such.

|      The  descriptions  of the  include  files referenced  by the
| relation_manager_  have  been  updated  to  reflect  the  current
| implementations.  The following corrections have been made:

| 1)   The  relation_search_specification structure  is declared in
|      dm_relation_spec.incl.pl1.
| 2)   The flags structure used by  the create_index entry point is
|      the     relation_index_flags    structure     declared    in
|      dm_relation_index_flags.incl.pl1.

  4 DESCRIPTION OF THE OPERATIONS

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Name:  relation_manager_

  Manages  tuples  in a  relation.   A relation  is comprised  of a
  record collection containing all of  the "tuples" of the relation
  and  some  number  of  index  collections.   An  index  has  keys
  containing one or  more fields, where each field  is an attribute
  of the relation (field of  the record collection).  The index key
  fields may be in any order.

  There are several types of  search specifications.  A spec can be |
  numeric positioning or  a search on values.  It  can be absolute, |
  done by starting  at the beginning or end of  the relation, or it |
  can be  relative, done by  starting at a position  specified by a |
  cursor.  The various structures used are described in Appendix A. |

  A number of the entries of the relation_manager_ accept or return
  data    in    the    form    of    a    simple_typed_vector,    a
  general_typed_vector, a  typed_vector_list, a typed_vector_array, |
  or  an element_id_list  structure.  The  include files  for these |
  structures are described in Appendix B.                           |

  Data management data types

  There are  several data types supported  in the relation_manager_
  module.   They  are specified  using Multics  standard descriptor
  structures.  The supported data types are:

       Real binary              - data types 1 through 4
       Complex binary           - data types 5 through 8
       Real decimal             - data types 9 and 10
       Complex decimal          - data types 11 and 12
       Strings                  - data types 19 through 22
       Unsigned real binary     - data types 33 and 34
       Real decimal             - data types 43 and 44
       Complex decimal          - data types 45 and 46

  All data must  be scalar (i.e., arrays are  not supported).  Both
  aligned and unaligned data is valid.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$close

  Decrements  the  count  of  openings for  this  relation  in this
  process by one.  If the count goes to zero, the file in which the
  relation resides  is closed and  any storage associated  with the
  opening is freed.

  Usage

       dcl relation_manager_$close entry (bit(36) aligned, fixed
            bin(35));

       call relation_manager_$close (rel_opening_id, code);

  where:

  rel_opening_id               (Input)
     is  the opening  identifier for  the relation  which is  to be
     closed.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$create_cursor

  Allocates a relation  cursor in the work_area.  The  cursor is to
  be used in subsequent calls to other relation_manager_ entries to
  identify the relation on which to  operate and to hold a position
  in a  relation.  The position  held by a  relation_cursor is only
  valid for repeated uses of  the same relation specification.  The
  caller is  responsible for destroying  the cursor by  calling the
  destroy_cursor operation  or by releasing  the area in  which the
  cursor is allocated.

  Usage

       dcl relation_manager_$create_cursor entry (bit(36) aligned,
            ptr, ptr, fixed bin(35));

       call relation_manager_$create_cursor (rel_opening_id,
            work_area_ptr, relation_cursor_ptr, code);

  where:

  rel_opening_id               (Input)
     is the opening identifier of the relation.

  work_area_ptr                (Input)
     is a  pointer to an  extensible area in which  to allocate the
     cursor.  The area  must also be a freeing  area, i.e., defined
     with the no_freeing flag off.

  relation_cursor_ptr          (Output)
     is  a  pointer  to   the  relation_cursor  allocated  by  this
     operation.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$create_index

  Creates  an index  for a  relation using  a specified  set of the
  relation's  attributes.  The  attribute identifiers  are given in
  the order  in which they are  to appear in the  indexed fields of
  the key of the index being created.  If the relation contains any
  tuples when this operation is invoked,  then all of the tuples of
  the  relation are  processed and keys  for each are  put into the
  index.   It is  possible to  invoke this  operation such  that it
  simply  returns an  error in this  case, instead  of creating and
  filling the new  index.  In any event, it is  never the case that
  there exists a tuple in a relation which is not indexed in all of
  the indices defined for that relation.

  Usage

       dcl relation_manager_$create_index entry (bit(36) aligned,
            ptr, bit(36) aligned, fixed bin(17), bit(36) aligned,
            fixed bin(35));

       call relation_manager_$create_index (rel_opening_id,
            id_list_ptr, flags, style, index_collection_id, code);

  where:

  rel_opening_id               (Input)
     is the opening identifier of the relation.

  id_list_ptr                  (Input)
     is a pointer  to an id_list structure which  contains an array
     of the attribute  identifiers to be placed in  the index.  The
     order in which the attribute identifiers are given is the same
     order that the  attributes will appear in the  index key.  The
     identifier of an attribute is the position of the attribute in
     the                 create_relation                operation's
|    typed_vector_array.dimension_table.

  flags                        (Input)
|    is a structure containing bits for controlling the creation of
|    the        index.         It       is        declared       in
|    dm_relation_index_flags.incl.pl1.  (See Appendix B).

  style                        (Input)
     is the  style of index  management to be used  for this index.
     The  defined  styles  are:    "multi-field  sorting"  (1)  and
     "multi-field  non-sorting"  (2).  Currently,  only style  1 is
     supported.  Style 2 will be a hash index.

  index_collection_id          (Output)

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     is  the identifier  assigned by index_manager_  when called by
     relation_manager_ to create the index.  Only the index manager
     should ever have need to do this directly.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$create_relation

| Creates and opens a relation in a specified file.  The attributes
  which make up tuples of the  relation are specified at this time.
  No   indices   are   created,   these  are   created   using  the
  "create_index" operation.

  Usage

       dcl relation_manager_$create_relation entry (char(*),
            char(*), ptr, ptr, bit(36) aligned, bit(36) aligned,
            fixed bin(35));

       call relation_manager_$create_relation (rel_dir, rel_name,
            rel_creation_info_ptr, typed_vector_array_ptr,
            rel_opening_id, record_collection_id, code);

  where:

  rel_dir                      (Input)
     is the directory in which to create the relation.

  rel_name                     (Input)
     is the name of the relation to be created.

  rel_creation_info_ptr        (Input)
|    is a  pointer to the rel_creation_info  structure (declared in
|    dm_rel_creation_info.incl.pl1) which determines the attributes
|    of  the file  being created,  as well  as the  method used for
|    storing it.

  typed_vector_array_ptr       (Input)
     is  a   pointer  to  a   typed_vector_array  structure.   This
     structure contains  a dimension_table sub-structure,  which is
     an  array of  descriptions of  attributes.  Each  entry in the
     array contains a name field (the  name of the attribute) and a
     descriptor_ptr field (a pointer to a Multics descriptor).  The
     name field  is the name of  each attribute; the descriptor_ptr
     defines  the data  type of  each attribute.   The rest  of the
     typed_vector_array is currently not used.

  rel_opening_id               (Output)
     is the opening identifier of the relation.

  record_collection_id         (Output)
     is the collection identifier  for the record collection, which
     holds  the  data  of  the tuples,  in  contrast  to  the index
     collections which  index the data in  the tuples.  Although no
     indices  are created  at this  time, the  record collection is

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     created.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$create_subset_index (unimplemented)

  Creates an  index containing the identifiers  of the tuples which
  satisfy the search specification as  a subset.  This index is for
  use  in the  subsets portion of  the specification.   The keys in
  this index are composed of a single field, the tuple identifier.

  Usage

       dcl relation_manager_$create_subset_index entry (ptr, ptr,
            bit(36) aligned, ptr, bit(36) aligned, fixed bin(35));

       call relation_manager_$create_subset_index
            (relation_cursor_ptr, specification_ptr,
            subset_file_opening_id, id_list_ptr, subset_index_id,
            code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  specification_ptr            (Input)
     is a pointer to a specification.

  subset_file_opening_id       (Input)
     is the file in which the subset index is to be placed.

  id_list_ptr                  (Input)
     is  a  pointer  to  an  id_list  structure  which  defines the
     relationship between  the fields in  the index from  which the
     subset is  being extracted and  the fields of the  keys of the
     subset index.  id_list.id(N) is the identifier of the field in
     the  "source" index  which is associated  with field  N of the
     subset index.  The id_list must  specify at least one field to
     be extracted from the source index.

  subset_index_id              (Output)
     is the index_id of the subset index created by this operation.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$delete_tuple_by_id

  Deletes  the  tuple  identified by  a  tuple id  and  updates all
  indices for the relation to reflect its absence.

  Usage

       dcl relation_manager_$delete_tuple_by_id entry (ptr, bit(36)
            aligned, fixed bin(35));

       call relation_manager_$delete_tuple_by_id                    |
            (relation_cursor_ptr, tuple_id, code);                  |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  tuple_id                     (Input)                              |
     is the identifier of the tuple to be deleted.                  |

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$tuple_not_found_id
        if the specified tuple is not present.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$delete_tuples_by_id

  Deletes all of  the tuples identified in a list  of tuple ids and
  updates all indices for the relation to reflect their absence.

  Usage

       dcl relation_manager_$delete_tuples_by_id entry (ptr, ptr,
            fixed bin(35), fixed bin(35));

|      call relation_manager_$delete_tuples_by_id
|           (relation_cursor_ptr, element_id_list_ptr,
|           number_of_tuples_processed, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  element_id_list_ptr          (Input)
     is a pointer to an element_id_list structure which contains an
     array of identifiers of tuples to be deleted.

| number_of_tuples_processed   (Output)
     is the number of tuples that were deleted.

  code                         (Output)
     is a standard system error code.  It can be:
        dm_error_$tuple_not_found_id if the  specified tuple is not
        present.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$delete_tuples_by_spec

  Deletes a set of tuples  identified by a search specification and
  updates  all of  the indices  for the  relation to  reflect their
  absence.

  Usage

       dcl relation_manager_$delete_tuples_by_spec entry (ptr, ptr,
            fixed bin(35), fixed bin(35));

       call relation_manager_$delete_tuples_by_spec                 |
            (relation_cursor_ptr, specification_ptr,                |
            number_of_tuples_processed, code);                      |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  specification_ptr            (Input)
     is a pointer to a search specification structure.              |

  number_of_tuples_processed   (Output)
     is the number of tuples that were deleted.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$invalid_cursor_position                              |
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

     dm_error_$tuple_not_found
        if no tuples satisfied the specification constraints.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$destroy_cursor

  Frees the storage occupied  by a relation_cursor.  This operation
  may  not be  necessary, depending on  the application,  as it may
  prove easier to just throw away the work_area.

  Usage

       dcl relation_manager_$destroy_cursor entry (ptr, ptr, fixed
            bin(35));

       call relation_manager_$destroy_cursor (relation_cursor_ptr,
            work_area_ptr, code);

  where:

  relation_cursor_ptr          (Input/Output)
     is a pointer to the cursor  to be destroyed by this operation.
     The value is set to null on output.

  work_area_ptr                (Input)
     is a pointer to the area in which the cursor is allocated.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$destroy_index

  Destroys an index associated with  a particular relation.  All of
  the space occupied by the index is freed.

  Usage

       dcl relation_manager_$destroy_index entry (bit(36) aligned,
            bit(36) aligned, fixed bin(35));

       call relation_manager_$destroy_index (rel_opening_id,
            index_collection_id, code);

  where:

  rel_opening_id               (Input)
     is the opening identifier of  the relation associated with the
     index being destroyed.

  index_collection_id          (Input)
     is the index_collection_id of the index being destroyed.

  code                         (Output)
     is a standard system error code.

  Notes

  Destroying  an index  makes all  existing cursors  for that index
  useless and the caller must not attempt to use them subsequent to
  index destruction, as the result of such a use is undefined.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$destroy_relation_by_opening

  Destroys a relation identified  by a relation opening identifier.
  All of the storage associated with the relation is freed.

  Usage

       dcl relation_manager_$destroy_relation_by_opening entry
            (bit(36) aligned, fixed bin(35));

       call relation_manager_$destroy_relation_by_opening
            (rel_opening_id, code);

  where:

  rel_opening_id               (Input)
     is the opening identifier of the relation.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$destroy_relation_by_path

  Destroys a relation identified by a pathname.  All of the storage |
  associated with the relation is freed.                            |

  Usage

       dcl relation_manager_$destroy_relation_by_path entry
            (char(*), char(*), fixed bin(35));

       call relation_manager_$destroy_relation_by_path (rel_dir,
            rel_name, code);

  where:

  rel_dir                      (Input)
     is the directory of the relation to be destroyed.

  rel_name                     (Input)
     is the entry name of the relation to be destroyed.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_count

  Gets  the count  of an  arbitrary set of  tuples as  defined by a
  specification and cursor.

  Usage

       dcl relation_manager_$get_count entry (ptr, ptr, fixed
            bin(35), fixed bin(35));

|      call relation_manager_$get_count (relation_cursor_ptr,
|           specification_ptr, tuple_count, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  specification_ptr            (Input)
     is a pointer to a specification structure.  If null, the count
     of all tuples is returned.

| tuple_count                  (Output)
     is  the   number  of  tuples  which   are  identified  by  the
     specification and cursor.

  code                         (Output)
     is a standard system error code.  It can be:

|    dm_error_$invalid_cursor_position
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_cursor_area_ptr                     |

  Returns a pointer to the area in which the cursor is allocated.   |

  Usage                                                             |

       dcl relation_manager_$get_cursor_area_ptr entry (ptr)        |
            returns (ptr);                                          |

       area_ptr = relation_manager_$get_cursor_area_ptr             |
            (relation_cursor_ptr);                                  |

  where:                                                            |

  relation_cursor_ptr          (Input)                              |
     is a pointer to a cursor for the relation.                     |

  area_ptr                     (Output)                             |
     is a pointer to the area in which the cursor is allocated.     |

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

| Entry:  relation_manager_$get_cursor_opening_id

| Returns the opening identifier of the relation.

| Usage

|      dcl relation_manager_$get_cursor_opening_id entry (ptr)
|           returns (bit(36) aligned);

|      rel_opening_id = relation_manager_$get_cursor_opening_id
|           (relation_cursor_ptr);

| where:

| relation_cursor_ptr          (Input)
|    is a pointer to a cursor for the relation.

| rel_opening_id               (Output)
|    is the opening identifier of the relation.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_description

  Returns  a description  of the specified  relation.  The relation |
  must be open.                                                     |

  Usage

       dcl relation_manager_$get_description entry (bit(36)
            aligned, ptr, ptr, fixed bin(35));

       call relation_manager_$get_description (rel_opening_id,      |
            work_area_ptr, relation_description_ptr, code);         |

  where:

  rel_opening_id               (Input)
     is the opening identifier of the relation.

  work_area_ptr                (Input)
     is a pointer  to an area in which  the relation_description is
     to be allocated.  The area may be extensible.

  relation_description_ptr     (Output)
     is a  pointer to the  relation_description structure, declared |
     in dm_relation_description.incl.pl1.                           |

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_duplicate_key_count

  Gets    the   number    of   keys    that   have    their   first
  number_of_duplication_fields identical  to some other  key's same
  fields.   Keys that  satisfy that  constraint for  fewer than all
  fields are called "partial  duplicates".  Complete duplicates are
  not possible in an index managed through relation_manager_.

  Usage

       dcl relation_manager_$get_duplicate_key_count entry (ptr,
            bit(36) aligned, fixed bin(17), fixed bin(35), fixed
            bin(35));

|      call relation_manager_$get_duplicate_key_count
|           (relation_cursor_ptr, index_collection_id,
|           number_of_duplication_fields, tuple_count, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  index_collection_id          (Input)
     is the collection identifier of  the index for which to obtain
     the count of duplicate keys.

  number_of_duplication_fields (Input)
     is  the number  of fields, starting  with the  first field, of
     keys to be checked for duplication.   A value of -1 means that
     all fields are to be considered.

| tuple_count                  (Output)
     is the number of keys found to be partial duplicates under the
     given constraints.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_index_id                            |

  Returns the  identifier of the index  created by the create_index |
  entry point.                                                      |

  Usage                                                             |

       dcl relation_manager_$get_index_id entry (ptr, ptr) returns  |
            (bit(36) aligned);                                      |

       index_id = relation_manager_$get_index_id                    |
            (relation_cursor_ptr, id_list_ptr);                     |

  where:                                                            |

  relation_cursor_ptr          (Input)                              |
     is a pointer to a cursor in the relation.                      |

  id_list_ptr                  (Input)                              |
     is a pointer  to an id_list structure which  contains an array |
     of the attribute  identifiers to be placed in  the index.  The |
     order in which the attribute identifiers are given is the same |
     order that the  attributes will appear in the  index key.  The |
     identifier of an attribute is the position of the attribute in |
     the                 create_relation                operation's |
     typed_vector_array.dimension_table.                            |

  index_id                     (Output)                             |
     is the identifier  of the index.  If no  index in the relation |
     matches the id_list, a value of "0"b is returned.              |

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_max_and_min_attributes (unimplemented)

  Gets the  maximum value and  the minimum value  in each attribute
  specified   over   all   of   the   tuples   which   satisfy  the
  caller-provided specification and cursor.

  Usage

       dcl relation_manager_$get_max_and_min_attributes entry (ptr,
            ptr, ptr, ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_max_and_min_attributes
            (relation_cursor_ptr, specification_ptr, id_list_ptr,
            work_area_ptr, min_typed_vector_ptr,
            max_typed_vector_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  specification_ptr            (Input)
     is a pointer to a specification structure which identifies the
     tuples.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes to be included in the operation.

  work_area_ptr                (Input)
     is a  pointer to an area  (of any kind) in  which the returned
     typed_vectors will be allocated.

  min_typed_vector_ptr         (Output)
     is a pointer to a simple_typed_vector structure which contains
     the minimum values of the  specified tuples for the attributes
     identified in the id_list.

  max_typed_vector_ptr         (Output)
     is a pointer to a simple_typed_vector structure which contains
     the maximum values of the  specified tuples for the attributes
     identified in the id_list.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_population

  Gets  the number  of tuples in  the relation.  This  count is not
  guaranteed  to be  exact, but  in almost  all cases  will be very
  close.   The precision  of the count  is compromised  in order to
  make the  operation a fast  one.  If an exact  count is required,
  use relation_manager_$get_count.

  Usage

       dcl relation_manager_$get_population entry (ptr, fixed
            bin(35), fixed bin(35));

       call relation_manager_$get_population (relation_cursor_ptr,
            tuple_count, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  tuple_count                  (Output)
     is the number  of tuples in the relation.   This number is not
     guaranteed to be exact, but will generally be quite close.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

| Entry:  relation_manager_$get_record_collection_id

| Returns the identifier of the record collection.

| Usage

|      dcl relation_manager_$get_record_collection_id entry (ptr)
|           returns (bit(36) aligned);

|      record_collection_id =
|           relation_manager_$get_record_collection_id
|           (relation_cursor_ptr);

| where:

| relation_cursor_ptr          (Input)
|    is a pointer to a cursor in the relation.

| record_collection_id         (Output)
|    is the identifier of the record collection.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuple_by_id

  Gets the value of the tuple specified by a tuple id.

  Usage

       dcl relation_manager_$get_tuple_by_id entry (ptr, bit(36)
            aligned, ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuple_by_id (relation_cursor_ptr,
            tuple_id, id_list_ptr, work_area_ptr,
            simple_typed_vector_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  tuple_id                     (Input)
     is  a  tuple  identifier  which  specifies  the  tuple  to  be
     retrieved.

  id_list_ptr                  (Input)
     is  a  pointer  to  an  id_list  structure,  specifying  which
     attributes of the tuple are to be returned.

  work_area_ptr                (Input)
     is  a  pointer to  an  area in  which  the simple_typed_vector
     containing the retrieved tuple is allocated.  Only return data
     are  allocated in  this area.  The  return area may  be of any
     type.

  simple_typed_vector_ptr      (Input/Output)                       |
     is a pointer to a simple_typed_vector containing the specified
     tuple.   It can  specify a pre-allocated  structure into which |
     the retrieved data is stored; otherwise this pointer should be |
     set  to  null on  input in  which case  the structure  will be |
     allocated   by  relation_manager_.    The  simple_typed_vector |
     structure  has only  the attributes specified  in the id_list,
     and the attribute (or dimension)  values are in the same order
     as  in  the id_list.   If  id_list_ptr is  equal to  null, the
     attributes are returned in the  order in which attributes were
     specified when the relation was created.

  code                         (Output)
     is a standard system error code.  It can be:

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     dm_error_$tuple_not_found_id
        if the specified tuple is not present.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuple_id

  Gets the identifiers of  tuples which satisfy the caller-provided
  constraints.   The  constraints  are satisfied  by  searching the
  indices and/or record collection identified in the specification.
  If an index search fails to  satisfy all of the constraints in an
  and-group, the  remaining constraints are  satisfied by searching
  the  record collection  containing the  actual tuples.   Only the
  tuples  which  satisfied the  index search  are examined  in this
  record  collection search.   This operation  is identical  to the
  "get_tuple_by_spec"  operation  except  that   a  list  of  tuple
  identifiers is returned instead of a list of tuples (i.e.  a list
  of values of tuples).

  Usage

       dcl relation_manager_$get_tuple_id entry (ptr, ptr, ptr,
            ptr, fixed bin(35));

       call relation_manager_$get_tuple_id (relation_cursor_ptr,
            specification_ptr, caller_area_ptr,
            element_id_list_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple for which an id was retrieved.

  specification_ptr            (Input)
     is a  pointer to the specification  structure which identifies
     the tuples.

  return_area_ptr              (Input)
     is a  pointer to an  area in which the  element_id_list may be
     allocated.

  element_id_list_ptr          (Input/Output)
     Input
        may be null or a pointer to a pre-allocated element_id_list |
        structure.  If a null value is supplied, element_id_list is
        allocated  in  the  supplied  return  area.   If  non-null,
        element_id_list.number_of_elements is changed to the number
        of tuples found, and  element_id_list.id is filled with the
        identifiers of  the tuples found.   It is not  assumed that
        the  value  of element_id_list.number_of_elements  on input
        represents an  upper bound on the  number of identifiers to
        return.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     Output
        is a pointer to  an element_id_list structure, containing a
        list of the tuple identifiers found by the search.

  code                         (Output)
     is a standard system error code.  It can be:

|    dm_error_$invalid_cursor_position
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

     dm_error_$tuple_not_found
        if no tuples satisfied the specification constraints.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuples_and_ids

  Gets the values and identifiers  of tuples which satisfy a search |
  specification  and  returns  them  in  a  typed_vector_list.  The |
  constraints are satisfied by  searching the indices and/or record
  collection identified  in the specification.  If  an index search
  fails   to  satisfy   all  of  the   constraints,  the  remaining
  constraints  are  satisfied  by searching  the  record collection
  containing the actual tuples.  Only  the tuples which satisfy the
  index search are examined in this record collection search.

  Usage

       dcl relation_manager_$get_tuples_and_ids entry (ptr, ptr,
            ptr, ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuples_and_ids
            (relation_cursor_ptr, specification_ptr, id_list_ptr,
            caller_area_ptr, element_id_list_ptr,
            typed_vector_list_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple retrieved.

  specification_ptr            (Input)
     is a pointer to a specification structure which identifies the
     tuples.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes    of   the    tuples   to    be   returned.    The
     simple_typed_vector structures which contain the returned data
     have  only  the  attributes  specified  in  id_list,  and  the
     attribute (or dimension) values are  in the same order as they
     are "named" in id_list.

  caller_area_ptr              (Input)
     is  a pointer  to an  area in  which the  typed_vector_list of
     retrieved  tuples will  be placed.   This can  be any  type of
     area.   An extensible,  non-freeing area  allows for  the most
     data and the fastest allocation scheme.

  element_id_list_ptr          (Input/Output)
     Input
        may be null or a pointer to a pre-allocated element_id_list |

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

        structure.  If a null value is supplied, element_id_list is
        allocated  in  the  supplied  return  area.   If  non-null,
        element_id_list.number_of_elements is changed to the number
        of tuples found, and  element_id_list.id is filled with the
        identifiers of  the tuples found.   It is not  assumed that
        the  value  of element_id_list.number_of_elements  on input
        represents an  upper bound on the  number of identifiers to
        return.
     Output
        is a  pointer to an element_id_list  structure containing a
        list of the tuple identifiers found by the search.

| typed_vector_list_ptr        (Input/Output)
|    Input
|       specifies a pre-allocated  typed_vector_list into which the
|       retrieved data is stored;  otherwise this pointer should be
|       set to null on input in  which case it will be allocated by
|       the relation_manager_.
|    Output
|       is a pointer to  the typed_vector_list structure containing
|       pointers   to  simple_typed_vectors   which  represent  the
|       returned tuples.

  code                         (Output)
     is a standard system error code.  It can be:

|    dm_error_$invalid_cursor_position
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

     dm_error_$tuple_not_found
        if no tuples satisfied the specification constraints.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuple_array_and_ids

  Gets the values and identifiers  of tuples which satisfy a search
  specification and returns them in a typed_vector_array.

  Usage

       dcl relation_manager_$get_tuple_array_and_ids entry (ptr,
            ptr, ptr, ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuple_array_and_ids
            (relation_cursor_ptr, specification_ptr, id_list_ptr,
            caller_area_ptr, element_id_list_ptr,
            typed_vector_array_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple for which an id was retrieved.

  specification_ptr            (Input)
     is a pointer to a specification structure which identifies the
     tuples.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes of the tuples to be returned.

  caller_area_ptr              (Input)
     is  a pointer  to an area  in which  the typed_vector_array of
     retrieved tuples will be placed.

  element_id_list_ptr          (Input/Output)
     Input
        may be null or a pointer to a pre-allocated element_id_list
        structure.  If a null value is supplied, element_id_list is
        allocated  in  the  supplied  return  area.   If  non-null,
        element_id_list.number_of_elements is changed to the number
        of tuples found, and  element_id_list.id is filled with the
        identifiers of  the tuples found.   It is not  assumed that
        the  value  of element_id_list.number_of_elements  on input
        represents an  upper bound on the  number of identifiers to
        return.
     Output
        is a  pointer to an element_id_list  structure containing a
        list of the tuple identifiers found by the search.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  typed_vector_array_ptr       (Input/Output)
     Input
        specifies a pre-allocated typed_vector_array into which the
        retrieved data is stored;  otherwise this pointer should be
        set to null on input in  which case it will be allocated by
        the relation_manager_.
     Output
        is a pointer to the typed_vector_array structure containing
        the retrieved tuples.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuple_array_by_id

  Gets the values  of tuples identified in a list  of tuple ids and
  returns them in a typed_vector_array.

  Usage

       dcl relation_manager_$get_tuple_array_by_id entry (ptr, ptr,
            ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuple_array_by_id
            (relation_cursor_ptr, element_id_list_ptr, id_list_ptr,
            work_area_ptr, typed_vector_array_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple for which an id was retrieved.

  element_id_list_ptr          (Input)
     is  a pointer  to an  element_id_list structure,  containing a
     list of tuple identifiers to be retrieved.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes of the tuples to be returned.

  work_area_ptr                (Input)
     is  a pointer  to an area  in which  the typed_vector_array of
     retrieved tuples will be placed.

  typed_vector_array_ptr       (Input/Output)
     Input
        specifies a pre-allocated typed_vector_array into which the
        retrieved data is stored;  otherwise this pointer should be
        set to null on input in  which case it will be allocated by
        the relation_manager_.
     Output
        is a pointer to the typed_vector_array structure containing
        the retrieved tuples.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuple_array_by_spec

  Gets   the  values   of  the   tuples  identified   by  a  search
  specification and returns them in a typed_vector_array structure.

  Usage

       dcl relation_manager_$get_tuple_array_by_spec entry (ptr,
            ptr, ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuple_array_by_spec
            (relation_cursor_ptr, specification_ptr, id_list_ptr,
            caller_area_ptr, typed_vector_array_ptr, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple for which an id was retrieved.

  specification_ptr            (Input)
     is a pointer to a specification structure which identifies the
     tuples.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes of the tuples to be returned.

  caller_area_ptr              (Input)
     is  a pointer  to an area  in which  the typed_vector_array of
     retrieved tuples will be placed.

  typed_vector_array_ptr       (Input/Output)
     Input
        specifies a pre-allocated typed_vector_array into which the
        retrieved data is stored;  otherwise this pointer should be
        set to null on input in  which case it will be allocated by
        the relation_manager_.
     Output
        is a pointer to the typed_vector_array structure containing
        the retrieved tuples.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuples_by_id

  Gets the values  of the tuples identified in a  list of tuple ids
  and returns them in a typed_vector_list.                          |

  Usage

       dcl relation_manager_$get_tuples_by_id entry (ptr, ptr, ptr,
            ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuples_by_id                      |
            (relation_cursor_ptr, element_id_list_ptr, id_list_ptr, |
            work_area_ptr, typed_vector_list_ptr, code);            |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  element_id_list_ptr          (Input)
     is a  pointer to an element_id_list  structure which specifies
     the tuples to be retrieved.

  id_list_ptr                  (Input)
     is  a  pointer  to   an  id_list  structure  specifying  which
     attributes are to be returned  of the tuples identified in the
     element_id_list.   The  simple_typed_vector  structures  which
     contain the  returned data have only  the attributes specified
     in the id_list, and the attribute (or dimension) values are in
     the same order as in the id_list.

  work_area_ptr                (Input)
     is  a  pointer  to  an  area  in  which  the typed_vector_list
     containing  all of  the retrieved  tuples is  allocated.  Only
     returned data are allocated in this area.  The return area may
     be of any type.

  typed_vector_list_ptr        (Input)                              |
     is  a  pointer  to  a  typed_vector_list  structure containing
     pointers to simple_typed_vectors  which represent the returned
     tuples.  The structure must be pre-allocated by the caller and |
     contain  the  same number  of  vectors as  identifiers  in the |
     element_id_list.                                               |

  code                         (Output)
     is a standard system error code.  It can be:

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     dm_error_$tuple_not_found_id
        if the specified tuple is not present.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$get_tuples_by_spec

  Gets   the  values   of  the   tuples  identified   by  a  search
  specification and returns them  in a typed_vector_list structure. |
  The constraints are satisfied by searching the indices and/or the
  record collection  identified in the specification.   If an index
  search fails to  satisfy all of the constraints  in an and-group,
  the remaining  constraints are satisfied by  searching the record
  collection containing  the actual tuples.  Only  the tuples which
  satisfy the  index search are examined  in this record collection
  search.

  Usage

       dcl relation_manager_$get_tuples_by_spec entry (ptr, ptr,
            ptr, ptr, ptr, fixed bin(35));

       call relation_manager_$get_tuples_by_spec                    |
            (relation_cursor_ptr, specification_ptr, id_list_ptr,   |
            caller_area_ptr, typed_vector_list_ptr, code);          |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the current  position of the cursor is  at the last
     tuple retrieved.

  specification_ptr            (Input)
     is a pointer to a specification structure which identifies the
     tuples.

  id_list_ptr                  (Input)
     is  a   pointer  to  an  id_list   structure  identifying  the
     attributes    of   the    tuples   to    be   returned.    The
     simple_typed_vector structures which contain the returned data
     have  only  the  attributes  specified  in  id_list,  and  the
     attribute (or dimension) values are  in the same order as they
     are "named" in id_list.

  caller_area_ptr              (Input)                              |
     is  a pointer  to an  area in  which the  typed_vector_list of
     retrieved  tuples will  be placed.   This can  be any  type of
     area.   An extensible,  non-freeing area  allows for  the most
     data and the fastest allocation scheme.

  typed_vector_list_ptr        (Input/Output)                       |
     Input                                                          |
        specifies a pre-allocated  typed_vector_list into which the |

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

|       retrieved data is stored;  otherwise this pointer should be
|       set to null  in which case the structure  will be allocated
|       by the relation_manager_.
|    Output
        is a pointer to  the typed_vector_list structure containing
        pointers   to  simple_typed_vectors   which  represent  the
        returned tuples.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$invalid_cursor
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

     dm_error_$tuple_not_found
        if no tuples satisfied the specification constraints.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$modify_tuple_by_id

  Modifies a tuple identified by a tuple id and updates all indices |
  of the relation to reflect the new value of the tuple.            |

  Usage

       dcl relation_manager_$modify_tuple_by_id entry (ptr, bit(36)
            aligned, ptr, fixed bin(35));

       call relation_manager_$modify_tuple_by_id                    |
            (relation_cursor_ptr, tuple_id, typed_vector_ptr,       |
            code);                                                  |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  tuple_id                     (Input)                              |
     is the identifier of the tuple to be modified.

  typed_vector_ptr             (Input)
     is  a  pointer  to  either a  simple  or  general typed_vector
     structure.   The  dimensions  identified  in  the typed_vector
     structure are the attributes to be modified, and the values of
     the typed vector are the values to which the attributes are to
     be set.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$tuple_not_found_id
        if the specified tuple is not present.

     dm_error_$key_duplication
        if the modification would cause  duplicate keys in a unique
        index,  and may  have left an  index out of  synch with the
        collection       of      tuples.        A      call      to
        relation_manager_$modify_tuple_by_id  using   the  original
        value will succeed in restoring  the value of the tuple and
        any modified indices.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and the operation should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$modify_tuples_by_id

  Sets the  value of one  or more attributes  in all of  the tuples
  identified by a list of tuple identifiers.  For each index of the
  relation  which  contains one  or  more of  the  attributes being
  modified as part  of its key format, the  key associated with the
  old value(s)  of the attributes  is/are deleted and  new keys are
  inserted to correspond with the new value for the attributes.

  If the modification causes the new  tuple to have a duplicate key
  in   a   unique  index,   then  no   modification  is   made  and
  dm_error_$key_duplication  is  returned  in  the  code  argument.
  Tuples which had been successfully  modified up to this point are
  left modified.

  Usage

       dcl relation_manager_$modify_tuples_by_id entry (ptr, ptr,
            ptr, fixed bin(35), fixed bin(35));

       call relation_manager_$modify_tuples_by_id
            (relation_cursor_ptr, element_id_list_ptr,
            typed_vector_ptr, number_of_tuples_processed, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to a  cursor  for the  relation.   The current
     position is not changed by this operation.

  element_id_list_ptr          (Input)
     is a  pointer to a element_id_list  structure which identifies
     the tuples to be modified.

  typed_vector_ptr             (Input)
     is  a  pointer  to  either a  simple  or  general typed_vector
     structure.   The  dimensions  identified  in  the typed_vector
     structure are the attributes to be modified, and the values of
     the typed vector are the values to which the attributes are to
     be set.

  number_of_tuples_processed   (Output)
     is the number of tuples that were modified.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$tuple_not_found_id
        if the specified tuple is not present.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     dm_error_$key_duplication
        if the modification would cause  duplicate keys in a unique
        index,  and may  have left an  index out of  synch with the
        collection       of      tuples.        A      call      to
        relation_manager_$modify_tuple_by_id        with        the
        number_of_tuples_modified   +   1'th  element_id   and  its
        original value should resynch the relation.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and the operation should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$modify_tuples_by_spec (unimplemented)

| Modifies  the  tuples identified  by  a search  specification and
| updates all  indices of the  relation to reflect  the new values.
  If the modification causes the new  tuple to have a duplicate key
  in   a   unique  index,   then  no   modification  is   made  and
  dm_error_$key_duplication is returned in the code argument.

  Usage

       dcl relation_manager_$modify_tuples_by_spec entry (ptr, ptr,
            ptr, fixed bin(35), fixed bin(35));

       call relation_manager_$modify_tuples_by_spec
            (relation_cursor_ptr, specification_ptr,
            typed_vector_ptr, number_of_tuples_processed, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  specification_ptr            (Input)
     is  a  pointer  to  a  search  specification  structure  which
     identifies the tuples.

  typed_vector_ptr             (Input)
     is a pointer to either  a simple or general typed_vector.  The
     ids of  the dimensions in the  vector must be the  same as the
     identifiers for the attributes in the relation.

  number_of_tuples_processed   (Output)
     is the number of tuples modified in carrying out the requested
     modification.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$invalid_cursor
        if a relative specification is supplied but the cursor does
        not identify a valid tuple position.

     dm_error_$tuple_not_found
        if no tuples satisfied the specification constraints.

     dm_error_$key_duplication
        if the modification would cause  duplicate keys in a unique
        index.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and the operation should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$open

  Opens the  specified relation.  The  caller must open  a relation
  before  accessing the  relation.  Only  one relation  opening can
  exist for  a given relation  per process.  The file  in which the
  relation resides  is opened and opening  information is extracted
  from the relation header.

  It is not an error to attempt to open an already opened relation;
  the existing  opening identifier is  returned and a  count of the
  number of  openings is incremented  by one if such  an attempt is
  made.

  Usage

       dcl relation_manager_$open entry (char(*), char(*), bit(36)
            aligned, fixed bin(35));

       call relation_manager_$open (rel_dir, rel_entry,
            rel_opening_id, code);

  where:

  rel_dir                      (Input)
     is the pathname of the directory which contains the relation.

  rel_entry                    (Input)
     is the entryname of the relation.

  rel_opening_id               (Output)
     is the relation opening identifier.

  code                         (Output)
     is a standard system error code.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$put_tuple

  Puts a tuple  into a relation and updates all  of the indices for
  that relation to reflect the presence of the new tuple.

  Usage

       dcl relation_manager_$put_tuple entry (ptr, ptr, bit(36)
            aligned, fixed bin(35));

       call relation_manager_$put_tuple (relation_cursor_ptr,       |
            typed_vector_ptr, tuple_id, code);                      |

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  typed_vector_ptr             (Input)
     is  a  pointer  to  either a  simple  or  general typed_vector
     structure which contains the value  of the tuple to be stored.
     If a simple_typed_vector, the  attribute values are assumed to
     be  in the  same order  as specified  in the "create_relation"
     operation's typed_vector_array.

  tuple_id                     (Output)                             |
     is the identifier of the tuple just inserted.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$key_duplication
        if  an  index may  have  been left  out  of synch  with the
        collection       of      tuples.        A      call      to
        relation_manager_$delete_tuple_by_id with element_id should
        resynch the relation.

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and the operation should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$put_tuples

  Puts  a set  of tuples  into a  relation and  updates all  of the
  indices  for that  relation to  reflect the  presence of  the new
  tuples.

  Usage

       dcl relation_manager_$put_tuples entry (ptr, ptr, ptr,
            bit(36) aligned, fixed bin(35), fixed bin(35));

       call relation_manager_$put_tuples (relation_cursor_ptr,
            typed_vector_list_ptr, element_id_list_ptr,
            number_of_tuples_put, code);

  where:

  relation_cursor_ptr          (Input)
     is  a  pointer  to  a  cursor  for  the  relation.   After the
     operation, the cursor is left with no current position.

  typed_vector_list_ptr        (Input)
     is a  pointer to a typed_vector_list  structure which contains
     pointers  to simple_typed_vectors  representing the  new tuple
     values to be  stored.  The attribute values are  assumed to be
     in  the  same  order  as  specified  in  the "create_relation"
     operation's typed_vector_array.

  element_id_list_ptr          (Input/Output)
     is  a pointer  to a element_id_list  structure, which contains
     the identifiers  of the tuples just  inserted.  This structure
     must  be allocated  by the caller  to have the  same number of
     entries  as   are  in  typed_vector_list.   If   an  error  is
     encountered,   the   first   number_of_tuples_put  element_ids
     returned were successfully put.

  number_of_tuples_put         (Output)
     is the number of tuples successfully put.

  code                         (Output)
     is a standard system error code.  It can be:

     dm_error_$key_duplication
        if  an  index may  have  been left  out  of synch  with the
        collection       of      tuples.        A      call      to
        relation_manager_$delete_tuple_by_id                   with
        element_id_list.id   (number_of_tuples_put   +   1)  should
        resynch the relation.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

     Any   other  non-zero   code  may   have  left   the  relation
     inconsistent and the operation should be rolled back.

  _________________                               _________________

  relation_manager_                               relation_manager_
  _________________                               _________________

  Entry:  relation_manager_$set_scope

  Advises  the  relation_manager_  what  MRDS scope  setting  is in
  effect  for  a  relation.   If the  relation  is  protected, this
  information is passed along to the file_manager_ where it is used
  to  determine  what  automatic  locks  should  be  used.   If the
  relation is unprotected, the relation_manager_ directly locks the
  entire relation  before each operation  and unlocks it  after the
  operation.   This scope  setting is  used as  advice to determine
  what lock to use.  In the case  where a process has more than one
  opening  for  a  single  database, and  more  than  one  of these
  openings have active scope set on a relation, it is up to MRDS to
  determine the combined setting.

  This  operation is  to be used  whenever the combined  scope on a
  relation changes, whether scope is being set or being deleted.

  Usage

       dcl relation_manager_$set_scope entry (bit(36) aligned,
            bit(2) aligned, bit(2)aligned, fixed bin(35));

       call relation_manager_$set_scope (rel_opening_id,
            this_process_permission, other_processes_permission,
            code);

  where:

  rel_opening_id               (Input)
     is the opening identifier of the relation.

  this_process_permission      (Input)
     are the operations permitted in this process.  If the leftmost
     bit is on ("10"b or "11"b) read is permitted; if the rightmost
     is on ("01"b or "11"b) write is permitted.

  other_processes_permission   (Input)
     are the operations permitted  in other processes.  See "Notes"
     below.

  code                         (Output)
     is a standard system error code.

  Notes

     The following relation level locks  are used for the specified
  scope setting advices (R is "10"b; W  is "01"b; RW is "11"b; N is
  "00"b):



  This process   Other processes  Relation level lock
   permission      permission
  ------------   ---------------  -------------------
        R               N          Exclusive (X)
        R               R          Share (S)
        R               W, RW      Intend-share (IS)
        W, RW           N          Exclusive (X)
        W, RW           R          Share-intend-exclusive
                                          (SIX)
        W, RW           W, RW      Intend-exclusive (X)



                Appendix A - Specification Structures

       Searches are started with  the tuple following the "current"
  tuple as identified by the cursor as  either a key in an index or
  a record in a record collection.

  The following structures are used in specifying tuples.

  The specification_head structure

  The  following  structure  is  used in  specifying  keys.   It is
  declared in the dm_specification_head.incl.pl1 include file:

  dcl 1 specification_head         based (sh_ptr) aligned,
        2 version                  fixed bin(35),
        2 type                     fixed bin(17) unal,
        2 pad                      bit(18) unal,
        2 subset_specification_ptr ptr;

  where:

  version
     is  the version  of the structure.   The current  version is a
     static variable named SPECIFICATION_VERSION_4.

  type
     is  the  type of  the  specification.  There  are  four types:
     absolute  numeric  positioning, relative  numeric positioning,
     absolute (from  the "root") searching, and  relative (from the
     current  position  indicated  by a  cursor)  searching.  These
     constants are defined in dm_specification_head.incl.pl1.

  pad
     must be "0"b.

  subset_specification_ptr
     is  a  pointer  to  a  subset_specification  structure.   This
     structure  is  used to  constrain selected  keys to  either be
     members of a subset or not be members of a subset.

  The subset_specification structure

  Following is  the structure to  specify subset indices  and their
  relation  to  a  specification  of   keys.   It  is  declared  in
  dm_subset_specification.incl.pl1.



  dcl 1 subset_specification based (subset_specification_ptr),
        2 version            char (8),
        2 number_of_subsets  fixed bin,
        2 subset             (ss_number_of_subsets refer
                             (subset_specification
                              .number_of_subsets)),
           3 id_list_ptr      ptr,
           3 is_member        bit(1) unaligned,
           3 pad              bit(35) unaligned,
           3 cursor_ptr       ptr;

  where:

  version
     is the version of the structure.   The version is given by the
     internal static constant SUBSET_SPECIFICATION_VERSION_1.

  number_of_subsets
     is the  number of subsets used  in defining the specification.
     Subsets may be  used in either numeric or  value, and absolute
     or relative positioning.

  subset.id_list_ptr
     is  a  pointer  to  an  id_list  structure  which  defines the
     relationship of  the fields of  the subset index  to the index
     being searched.  id_list.id(I) is  the identifier of the field
     in the index being searched  which is associated with the I'th
     field of the subset index.

  subset.is_member
     if on, indicates that keys which this specification identifies
     must be found in this subset.   For a subset to have a (source
     index) key as a member, the subset index must contain as a key
     the data  which is found  in the attendant data  fields of the
     source index key.  This is a  special case of the more general
     subset  "membership"  definition  which allows  the  caller to
     define the way in which data from the source index is to match
     data in the subset index.  This special case is useful for the
     relation manager.

  subset.pad
     must be "0"b.

  subset.cursor_ptr
     is a pointer to a cursor for the subset index.

  The relation_search_specification structure

       This  structure is  used to search  for tuples  based on the
  values   of   particular   attributes.    It   is   declared   in |
  dm_relation_spec.incl.pl1.                                        |



| dcl 1 relation_search_specification aligned based (rss_ptr),
        2 head                    like specification_head,
        2 maximum_number_of_constraints
                                  fixed bin (17) unal,
        2 number_of_and_groups    fixed bin (17) unal,
        2 flags                   unal,
          3 return_unique_tuples  bit (1) unal,
          3 mbz                   bit (35) unal,
        2 range,
          3 type                  fixed bin (17),
          3 size                  fixed bin (17),
        2 and_group               (rss_number_of_and_groups refer
                                  (relation_search_specification
                                  .number_of_and_groups)),
          3 search_collection_id  bit (36) aligned,
          3 flags                 unal,
            4 collection_id_supplied
                                  bit (1) unal,
            4 mbz                 bit (17) unal,
          3 number_of_constraints fixed bin (17) unal,
          3 constraint            (rss_maximum_number_of_constraints
                                  refer (
                                  relation_search_specification
                                  .maximum_number_of_constraints)),
            4 field_id            fixed bin (17) unal,
            4 operator_code       fixed bin (17) unal,
            4 value_field_id      fixed bin (17) unal,
            4 mbz                 bit (18) unal,
            4 value_ptr           ptr;

  where:

  maximum_number_of_constraints
     is the number of field specifications to be allocated for each
     and_group.

  number_of_and_groups
     is the number of and_groups  used in the search specification.
     The elements  satisfied by each and_group  are joined by union
     to   obtain   the   complete   set  to   satisfy   the  search
     specification.

  flags.return_unique_tuples
     is  a  flag  which indicates,  if  on,  that no  tuple  can be
     selected  more  than  once.  It  is  possible for  a  tuple to
     satisfy the constraints of more than one and-group.

  flags.mbz
     is reserved for future use and must be "0"b.

  range.type



     is the type of range of the specified keys desired:
          0 - all
          1 - top
          2 - bottom

  range.size
     is the size  of the range.  If the type  is "all" (or 0), then
     the size  is ignored.  If the  type is "top" and  the value of
     size is  N, then the highest  N keys of the  keys selected are
     returned.  In the  case of "bottom", the lowest  N keys of the
     keys selected are returned.

  and_group.search_collection_id
     is the collection identifier of the index or record collection
     to use to satisfy the constraints of this and-group.

  and_group.flags.collection_id_supplied
     is     a    flag     which    indicates,     if    on,    that
     and_group.search_collection_id actually  contains a collection
     id.   If  this  flag   is  off,  relation_manager_  selects  a
     collection to use to satisfy the constraints.

  and_group.flags.mbz
     is reserved for future use and must be "0"b.

  and_group.number_of_constraints
     is  the  number  of  constraints  actually  in  use  for  this
     and_group.  Each constraint of the and_group must be satisfied
     in order for an element to be a member of the and_group.

  and_group.constraint.field_id
     is the id for the field being constrained.

  and_group.constraint.operator_code
     is the relationship the value of the desired keys must have to
     the  value specified  in this constraint.   The operator codes
     can be  dealt with as either  fixed binary number or  as a bit
     string  (which must  be converted  to a  fixed binary number).
     When considered  as a bit  string the meaning of  the bits are
     or'ed together.   The right-most bits are  given the following
     meaning:

        "00001"b - = (equals)
        "00010"b - > (greater than)
        "00100"b - ^ (not)
        "01000"b - regular expression match
        "10000"b - field may be absent

     An  "absent" field  always compares  to false  for any  of the
     other four comparisons.  If this  bit is on, an "absent" field
     will compare "true" and a "present" field will compare false.

     Some combinations of operators "bits"  are not defined to have



     any  meaning,  e.g.   "regular  expression  match"  or'ed with
     "greater  than".  The  complete definition of  the meanings of
     all  of  the combinations  of the  5 right-most  operator bits
     follows:

        1 - "00001"b - =
        2 - "00010"b - >
        3 - "00011"b - >=
        4 - "00100"b - ^
        5 - "00101"b - ^= (><)
        6 - "00110"b - ^> (<=)
        7 - "00111"b - ^>= (<)
        8 - "01000"b - regular expression match
        9 through 15 - undefined
        16 - "10000"b - field is absent from key
        17 - "10001"b - field is absent or =
        18 - "10010"b - field is absent or >
        19 - "10011"b - field is absent or >=
        20 - "10100"b - field is not absent
        21 - "10101"b - field is absent or ^> (<=)
        22 - "10110"b - field is absent or  ^=
        23 - "10111"b - undefined
        24 - "11000"b - if field is present, regular
                        expression match
        25 through 31 - undefined

  and_group.constraint.value_field_id
     if non-zero, is the identifier of  a field, the value of which
     is to  be compared with  the value of  the constraint.field_id
     field.  This is used to specify  a comparison of the values of
     two fields within a  tuple.  The value of constraint.value_ptr
     must be null.

  and_group.constraint.mbz
     is reserved for future use and must be "0"b.

  and_group.constraint.value_ptr
     if non-null, is a pointer to the value to be compared with the
     value  of  the  constraint.field_id  field.  This  is  used to
     specify a  comparison of the  value of a field  and a constant
     value.  The value  must be allocated according to  the DM data
     types.  The value of constraint.value_field_id must be zero.

  The relation_numeric_specification structure

  This structure is used when a search for tuples with a particular
  numeric   position   is  to   be   done.   It   is   declared  in
  dm_relation_spec.incl.pl1.



   dcl 1 relation_numeric_specification
                            based (
                            relation_numeric_specification_ptr),
         2 head             like specification_head,
         2 collection_id    bit (36) aligned,
         2 range_size       fixed bin (35),
         2 position_number  fixed bin (17) unal,
         2 pad              bit (18) unal;

  where:

  collection_id
     is  the   identifier  of  the  collection   (index  or  record
     collection)  over  which  to  position.   A  valid  collection
     identifier must be supplied.

  range_size
     is the number of tuples to return.

  position_number
     is interpreted according to the absolute or relative nature of
     the specification.  If absolute,  it is the position_number'th
     key  of  the  index  to  which  the  position  is  moved.   If
     position_number  is negative,  the keys  are counted backwards
     from  the  end  of  the index  for  position_number  keys.  If
     position_number is positive, the keys are counted forward from
     the beginning  of the index.   If the type is  relative, it is
     the position_number'th key from  the current position to which
     the  position is  moved.  If position_number  is negative, the
     position is  moved backwards from the  current position; if it
     is positive, it is moved forwards from the current position.

     If position_number moves the cursor beyond the index, i.e.  it
     is either too large or too  small, then the cursor is moved to
     the  beginning or  end of  the index  or record  collection as
     appropriate      and      dm_error_$beginning_of_index      or
     dm_error_$beginning_of_collection,  or  dm_error_$end_of_index
     or dm_error_$end_of_collection is returned.



                 Appendix B - Information Structures

  The element_id_list structure

       Contains  an array  of "bit(36)  aligned" identifiers  to be
  used  as record  ids, tuple  ids, key  ids, or  element ids.  Its
  declaration    follows,    and    it     can    be    found    in
  dm_element_id_list.incl.pl1.

       dcl 1 element_id_list    aligned based (element_id_list_ptr),
             2 version          fixed bin(35),
             2 number_of_ids    fixed bin(17),
             2 id               (eil_number_of_ids refer
                                (element_id_list.number_of_ids))
                                bit(36) aligned;

  where:

  version
     is    the     version    of    the     structure,    currently
     ELEMENT_ID_LIST_VERSION_1.

  number_of_ids
     is the number of identifiers.

  id
     is an array of element identifiers.

  The file_create_info structure

| This structure  describes the attributes  of the file  in which a
| newly created relation  will reside.  It is found  in the include
| file dm_file_create_info.incl.pl1.

  dcl  1 file_create_info     aligned based (file_create_info_ptr),
         2 version            bit (36),
         2 ci_size_in_bytes   fixed bin (35),
         2 blocking_factor    fixed bin,
         2 protected          bit unal,
         2 no_concurrency     bit unal,
         2 no_rollback        bit unal,
         2 mbz_1              bit (33) unal,
         2 mbz_2              (30) fixed bin (71);

  where:

  version
     is the current version of the  structure.  This must be set to
     FILE_CREATE_INFO_VERSION_1.



  ci_size_in_bytes
     is  the  control  interval  size of  the  new  file  in bytes.
     Currently, the only valid value for this parameter is 4096.

  blocking_factor
     is   the  number   of  control  intervals   in  each  segment.
     Currently, the only alternatives are 64 and 255.

  protected
     indiates,  if on  ("1"b), that access  to the file  must be on
     behalf of a running transaction.

  no_concurrency
     indicates,   if  on   ("1"b),  that   Data  Management  System
     concurrency control is not to be used.

  no_rollback
     indicates,  if on  ("1"b), that  before images  are not  to be
     taken when updating the file.

  mbz_1
     must be "0"b.  This is reserved for future use.

  mbz_2
     must be 0.  This is reserved for future use.

  The id_list structure

  The  id_list  structure  contains  an  array  of  "fixed bin(17)"
  identifiers,  which are  used to identify  attributes and fields.
  The declaration follows, and it is found in dm_id_list.incl.pl1.

  dcl 1 id_list          aligned based (id_list_ptr),
        2 version        fixed bin(35),
        2 number_of_ids  fixed bin(17),
        2 id             (il_number_of_ids refer
                         (id_list.number_of_ids))
                         fixed bin(17);

  where:

  version
     is the version of the structure, ID_LIST_VERSION_1.

  number_of_ids
     is the number of identifiers.

  id
     is an  array of identifiers,  used to identify  attributes and
     fields.



  The rel_creation_info structure

| This  structure is  used in  the creation  of a  relation.  It is
| declared in dm_rel_creation_info.incl.pl1.

| dcl 1 rel_creation_info      aligned based (
                               rel_creation_info_ptr),
        2 version              fixed bin (35),
        2 file_create_info_ptr ptr,
        2 esm_info_ptr         ptr,
        2 cism_info_ptr        ptr;

  where:

  version
|    is   the  version   of  the   structure  which   is  currently
|    REL_CREATION_INFO_VERSION_2.

  file_create_info_ptr
     is  a  pointer to  a  file_create_info structure  (declared in
     dm_file_create_info.incl.pl1).    This   structure   describes
     attributes of the file in  which the relation will reside.  If
     null, the described defaults are taken.

  esm_info_ptr
     is a pointer to a basic_esm_info structure.  This structure is
     declared  in the  dm_cm_esm_info.incl.pl1 include  file and is
     used  to  determine  certain  storage  methods  of  the record
|    collection,  namely  the maximum  length in  bits of  a tuple,
     whether tuples must be fixed-length, and whether tuples should
|    be  threaded  together.   If   a  null  pointer  is  supplied,
|    relation_manager_  figures  the  maximum length  based  on the
|    supplied descriptors.

  cism_info_ptr
     is    a   pointer    to   either    a   blocked_cism_info   or
     unblocked_cism_info  structure.   Both  are  declared  in  the
     include  file  dm_cm_cism_info.incl.pl1.    They  specify  the
     method of storing control  intervals in the record collection.
     If cism_info_ptr is null, the unblocked method is assumed.

  The relation_description structure

  Following   is  the   description  of   the  relation_description
  structure  found in  the dm_relation_description.incl.pl1 include
  file:



  dcl 1 relation_description   aligned based (                      |
                               relation_description_ptr),
        2 version              fixed bin (35),
        2 maximum_number_of_attributes_per_index
                               fixed bin (17) unal,
        2 number_of_attributes fixed bin (17) unal,
        2 number_of_indices    fixed bin (17) unal,
        2 maximum_attribute_name_length
                               fixed bin (17) unal,
        2 record_collection_id bit (36) aligned,
        2 attribute            (rd_number_of_attributes
                               refer (relation_description
                               .number_of_attributes))
          3 name               char (rd_maximum_attribute_name_length
                               refer (relation_description
                               .maximum_attribute_name_length))
                               varying,
          3 descriptor_ptr     ptr,
        2 index                (rd_number_of_indices
                               refer (relation_description
                               .number_of_indices)),
          3 collection_id      bit (36) aligned,
          3 style              fixed bin (17) unal,                 |
          3 number_of_attributes
                               fixed bin (17) unal,                 |
          3 flags,
            4 is_unique        bit (1) unal,
            4 is_primary       bit (1) unal,                        |
            4 pad              bit (34) unal,                       |
          3 attribute     (rd_maximum_number_of_attributes_per_index
                           refer (relation_description
                           .maximum_number_of_attributes_per_index))
                           fixed bin (17) unal;                     |

  where:

  version
     is the current  version of the structure which  must be set to
     RELATION_DESCRIPTION_VERSION_3.

  maximum_number_of_attributes_per_index
     is the maximum  number of attributes per index  and the extent
     of each relation_description.index.attribute array.

  number_of_attributes
     is the number of attributes in each tuple.

  number_of_indices
     is the number of indices defined for this relation.

  record_collection_id
     is the identifier of the record collection in which tuples are



     stored.

  attribute.name
     is the name of each  attribute.  Attribute names are specified
     when the relation is created.

  attribute.descriptor_ptr
     is a pointer to a Multics descriptor for each attribute.

  index.collection_id
     is the identifier of the index collection in which an index is
     stored.

  index.style
     is the style of index management employed by an index.

  index.number_of_attributes
     is  the  number  of  attributes  per  key  in  an  index.  The
     attributes  correspond  to fields  in  the key,  with  the key
     having one extra field for the tuple identifier.

  index.flags.is_unique
     is a  flag which indicates, if  on, that no two  keys can have
     the same values for all attributes.

  index.flags.is_primary
     is  a  flag which  indicates, if  on, that  this index  is the
     primary index of the relation.

  index.flags.pad
     is reserved for future use, and must be "0"b.

  index.attribute
     is  an  array  of  indices  into  the attribute_descriptor_ptr
     array, defining the attributes which make up the key.

  The relation_index_flags structure

  This structure is used to control the creation of an index by the
  relation_manager_.         It        is        declared        in
  dm_relation_index_flags.incl.pl1.

  dcl 1 relation_index_flags     aligned based
                                 (relation_index_flags_ptr),
        2 relation_must_be_empty bit (1) unaligned,
        2 index_is_clustering    bit (1) unaligned,
        2 index_is_unique        bit (1) unaligned,
        2 pad                    bit (33) unaligned;

  where:



  relation_must_be_empty
     indicates, if on,  that there must be no  data in the relation
     when this index is being created.

  index_is_clustering
     (not  implemented)  indicates,  if  on, that  the  index being
     created is to be used  to control physical placement of tuples
     in  the record  collection.  Tuples  are stored  physically in
     approximately the  same order as  the order maintained  by the
     index.  The  order is not exact  because scenarios exist where
     holding  rigidly to  the order would  cause a  wasteful use of
     space  and  performance degradation.   There  can only  be one
     clustering index  for a relation,  and it need  not be unique.
     If no clustering  index is defined for a  relation, tuples are
     stored in as close to chronological order as possible.

  index_is_unique
     indicates, if on,  that no key in the index  is a duplicate of
     another.

  The typed_vector structure

       There   are   two   formats   for   the   typed_vector,  the
  simple_typed_vector  and  the   general_typed_vector.   Both  are
  defined in vu_typed_vector.incl.pl1.   In the simple_typed_vector
  there is  only a pointer  for each dimension  value, no dimension
  identifier  is  provided.   It  can  be  used  when  all  of  the
  dimensions   in   a   typed_vector_array  are   present   in  the
  typed_vector.  The dimensions would be assumed to be in the order
  defined by the dimension_table of the typed_vector_array.

       In  the  general_typed_vector,  any  subset  of  the defined
  dimensions  may  be  present, hence  the  dimension.identifier is
  required.

  dcl 1 simple_typed_vector    based (simple_typed_vector_ptr),
        2 type                 fixed bin (17) unal,
        2 number_of_dimensions fixed bin (17) unal,
        2 dimension            (stv_number_of_dimensions refer
                               (simple_typed_vector
                               .number_of_dimensions)),
          3 value_ptr          ptr unal;

  dcl 1 general_typed_vector   based (general_typed_vector_ptr),
        2 type                 fixed bin (17) unal,
        2 number_of_dimensions fixed bin (17) unal,
        2 dimension            (gtv_number_of_dimensions refer
                               (general_typed_vector
                               .number_of_dimensions)),
          3 identifier         fixed bin (17) unal,
          3 pad                bit (18) unal,
          3 value_ptr          ptr unal;



  where:

  type
     indicates the  type of the vector  structure.  2 indicates the
     general_typed_vector  and 3  indicates the simple_typed_vector
     structure.

  number_of_dimensions
     is the number of dimensions present in the vector.

  dimension.identifier
     is the index in  the dimension_table of the typed_vector_array
     of the dimension.

  dimension.pad
     must be "0"b.

  dimension.value_ptr
     is a pointer to the value of the dimension.

  The typed_vector_array structure

       The         typed_vector_array         structure         (in
  vu_typed_vector_array.incl.pl1) is:

  dcl 1 typed_vector_array       based (typed_vector_array_ptr)
                                 aligned,
        2 version                fixed bin (35),
        2 number_of_dimensions   fixed bin (17),
        2 number_of_vectors      fixed bin (17),
        2 number_of_vector_slots fixed bin (17),
        2 maximum_dimension_name_length
                                 fixed bin (17),
        2 dimension_table        (tva_number_of_dimensions
                                 refer (typed_vector_array
                                 .number_of_dimensions)),
          3 name                 char (
                                 tva_maximum_dimension_name_length
                                 refer (typed_vector_array
                                 .maximum_dimension_name_length))
                                 varying,
          3 descriptor_ptr       ptr,
          3 cv_to_print          entry (ptr, ptr, ptr, fixed bin(35),
                                 char(*) varying, fixed bin(35)),
          3 cv_to_typed          entry (ptr, ptr, ptr, ptr,
                                 fixed bin(35)),
        2 vector_slot            (tva_number_of_vector_slots
                                 refer (typed_vector_array
                                 .number_of_vector_slots)) ptr;



  where:

  version
     is    the    version     of    this    structure,    currently
     TYPED_VECTOR_ARRAY_VERSION_2.

  number_of_dimensions
     is the number of dimensions in the dimension table.

  maximum_dimension_name_length
     is the  maximum length of  any of the dimensions  named in the
     dimension table.

  number_of_vectors
     is  the  number  of vector  slots  actually used  to  point at
     vectors.

  number_of_vector_slots
     is the number of vector slots allocated.

  dimension_table.name
     is the name of the dimension.

  dimension_table.descriptor_ptr
     is a pointer to standard Multics data type descriptor.

  dimension_table.cv_to_print
     is  an entry  for converting from  typed format  data to print
     format.

  dimension_table.cv_to_typed
     is an entry for converting from print format data to typed.

  vector_slot
     is a pointer to a typed_vector structure.

  The typed_vector_list structure

  The   declaration  and   description  of   the  typed_vector_list
  structure  follows   and  can  be  found   in  the  include  file
  dm_typed_vector_list.incl.pl1.



  dcl 1 typed_vector_list       aligned based (typed_vector_list_ptr),
        2 version               fixed bin (17),
        2 maximum_number_of_vectors
                                fixed bin (35),
        2 number_of_vectors     fixed bin (35),
        2 pad                   fixed bin (35),
        2 vector_ptr            (tvl_maximum_number_of_vectors
                                refer typed_vector_list
                                .maximum_number_of_vectors)
                                ptr;

  where:

  version
     is   the  version   of  the   structure  which   is  currently
     TYPED_VECTOR_LIST_VERSION_1,  declared  in  the  same  include
     file.

  maximum_number_of_attributes
     is the extent of the array of vector_ptrs.

  number_of_vectors
     is the actual number of vector_ptrs present.

  pad
     is reserved for future use and must be 0.

  vector_ptr
     is  an  array of  pointers to  simple_typed_vector structures,
     which are declared in vu_typed_vector.incl.pl1.