Chapter 2: The mr Routines




2.1 Introduction

In general, the mr routines allow you to open a table, add records to it, delete records from it, retrieve qualified records from it, and update records in it. All operations are performed one record at a time. Six major data pointers are involved:

  1. table_descriptors that point to opened tables.

  2. attribute_descriptors that point to attributes of an opened table.

  3. record_descriptors that point to records.

  4. qualification_descriptors that associate a qualification with an attribute or record.

  5. retrieval_descriptors that associate qualifications with tables.

  6. strings corresponding to the external formats of attribute values. The different formats of attribute values are discussed later in this chapter.

The first five data pointers should be declared as addr, and strings should be declared as char*. The table, attribute, record, and qualification descriptors are pointers to Empress internal structures. Although the addr data type is defined as char*, these pointers are not really strings and should not be used as such. The addr data type is used as a reminder of this.



2.2 Accessing the mr Routines

2.2.1 The Header File mscc.h

The header file mscc.h must be included at the beginning of each program using the mx routines. It has the correct definitions for all the mr (and mx) routines and a number of useful definitions of data types and constants. mscc.h also includes the Standard I/O Library, so there is no need to include this in your programs. The file is shown below.

Please note that the mscc.h file differs from version to version. For an exact reference, the file is located in $EMPRESSPATH/include directory.



   /***********************************************************************
    *      (c) Copyright   Empress Software Inc. 1983, 2006
    ***********************************************************************/

   #ifndef __MSCC_H

   #define __MSCC_H

   #ifdef __cplusplus
   extern "C" {
   #endif

   #include        <stdio.h>
   #include        "c.h"

   #include        <misc/public.h>
   #include        <usrmp/msdsqldt.h>
   #include        <usrfns/dtparvar.hx>
   #include        <api/mrapi.hx>
   #include        <api/msapi.hx>
   #include        <api/mxapi.hx>
   #include        <misc/init.hx>
   #include        <misc/mscc_com.h>
   #include        <misc/mxe.h>
   #include        <misc/mxtrig.h>


   #ifdef __cplusplus
   }
   #endif

   #endif  /* __MSCC_H */


2.2.2 Initialization and Cleanup

There are two ways to organize a program using the Empress mr routines:

  1. You can name the regular main procedure msmain. This will include a default main procedure which does the necessary initializations. msmain may have the parameters argc and argv as usual. Similarly, name the regular C exit procedure msexit.

  2. You can write your own main procedure, calling msinit to begin and msexit to end. These two procedures carry out various initialization and cleanup tasks.

    The msinit can be called several times during the execution of a program. Subsequent msinit calls should be preceeded, in general case, by a cleanup task (i.e. msend). However, this is not neccessary, and spawned processes can invoke msinit although msend hasn't been called previously.

The routine msclean allows you to put a procedure on the stack to be called immediately before the program exits.

2.2.3 Compiling and Linkings

Programs using the mr routines must be compiled using empcc or empc++. The effect of this is to ensure that Empress library routines are included in the compilation; in all other respects, empcc, for example, behaves similarly to cc.

Note that mscall statements may also be used in programs compiled by empcc or empc++. For example, the simplest way to create a new table in an application program is to use an mscall statement.



2.3 Internal, External, and File Attribute Formats

Throughout this section, references will be made to internal, external, and file formats of attribute values.

The external format is what is printed by a Query Language SELECT command. External format values are character strings.

The internal format is the format in which the value is manipulated by Empress, and does not necessarily correspond to the external format. For example, date (1) values are not manipulated as (for instance) "1 May 1998", nor are dollar values manipulated complete with dollar signs, asterisks, and commas.

Finally, there is the file format, which is the way the value is actually stored on disk by Empress. Application programs do not retrieve file format values.

Attribute values are normally retrieved in external format, though it is possible to retrieve integers and internal format values directly. Values are normally assigned to attributes in external format or as integers, though it is possible to assign an internal format value directly to an attribute.

To do arithmetic on external format (character string) retrieved values, they must first be converted to numeric values using sscanf, atof, etc. Note that dollar signs, asterisks, and so on must be removed from dollar values before converting them. A simple procedure for doing this, dollcvt, is presented in the next chapter.

Bulk data values are handled differently from other types. To output bulk values in external format (as in a Query Language SELECT) would require converting the bytes to hexadecimal characters, which is not what is generally needed. Instead, bulk data is normally output in internal format using the routine mrgeti. This routine is intended specifically for retrieving bulk data, though it can be used to get the internal format of any other type of data as well. The example voice.c in the next chapter illustrates the use of mrgeti to get bulk data in internal format.



2.4 Data Type Correspondences

The usual correspondence (subject to machine architecture) between Empress data types (also known as MS data types) and C language data types is given below. When retrieved values from a database are stored in C variables, the variables must be of the appropriate type.

Table 2-1 MS Data Type Correspondences for C

MS Data Type C Data Type
CHAR
CHARACTER
char[] (terminated by EOS)
SHORTINTEGER
SMALLINT
char
INTEGER
INT
short
LONGINTEGER long
DATE gen_date
DOLLAR unsigned char[]
REAL float
LONGFLOAT
DOUBLE PRECISION
double
FLOAT float : if decimal places <=6
double : if decimal places > 6
TEXT char[] (terminated by EOS)
BULK gen_binary*
DECIMAL
DEC
unsigned char[]
TIME gen_date
NLSCHAR
NLSCHARACTER
char[] (terminated by EOS)
NLSTEXT char[] (terminated by EOS)
MICROTIMESTAMP gen_date


Table 2-2 Generic Data Type Correspondences for C

Generic Data Type C Data Type
GENERIC CHAR char*
GENERIC INTEGER gen_integer
GENERIC DECIMAL gen_dec
GENERIC FLOAT gen_float
GENERIC DATE gen_date
GENERIC BOOLEAN gen_boolean
GENERIC EXTERNAL char*
GENERIC INTERVAL gen_date
GENERIC BINARY gen_binary*



2.5 Handling Normal Failures

There are situations in which the mr routines are properly unable to execute successfully, such as when record-level locking is in force for a table and a record which the routine needs to access is locked, or when the data which a routine attempts to insert into a table is disallowed because of range checking or a limited-duplicate index, or when inappropriate data is passed to one of the qualification routines.

Whether the calling program terminates or not when a routine fails depends on the routine. Routines that return a flag showing success or failure of the routine do not terminate on failure unless otherwise indicated. Routines that do not return a flag showing success or failure terminate on failure. Note that a given operation may often be handled by two routines, one that terminates the calling program on failure and one that does not.

For routine that does not terminate on failure, the variable mroperr is set to one of the MRER... codes listed in the header file mrerrno.h, and control is returned to the program. mroperr may be examined by the application program to determine why the routine failed, and something sensible done about it.

The mrerrno.h is listed below. Please note that this file differs from version to version. For an exact reference, the file is located in $EMPRESSPATH/include/usrmr directory.



   /***********************************************************************
    *  (c) Copyright Empress Software Inc. 1983, 2006
    ***********************************************************************/
   
   #define MRNOERR             0 /* no error indication*/
   #define MRERNAME            1 /* invalid table name */
   #define MREREXIST           2 /* table already exists */
   #define MRERNEXIST          3 /* table does not exist */
   #define MRERRPERM           4 /* no read permission on table */
   #define MRERWPERM           5 /* no read/write permission on tab */
   #define MRERBUSY            6 /* database/table lock busy */
   #define MRERVWOP            7 /* operation invalid on view */
   #define MRERVWDEF           8 /* invalid definition for view */
   #define MRERVWRECUR         9 /* recursive definition for view */
   #define MRERDBEXIST        10 /* not a database */
   #define MRERANAME          11 /* invalid attribute name */
   #define MRERAEXIST         12 /* attribute already exists */
   #define MRERANEXIST        13 /* attribute does not exist */
   #define MRERDTPAR          14 /* invalid data type/parameters */
   #define MRERINAME          15 /* invalid index name */
   #define MRERNULL           16 /* null value for attribute */
   #define MRERUDUP           17 /* duplicate value for attribute */
   #define MRERDUP            18 /* too many duplicate values */
   #define MRERCVT            19 /* bad value conversion for attr */
   #define MRERPRIV           20 /* no privilege for table */
   #define MRERAPRIV          21 /* no update privilege on attribute */
   #define MRERCRPRIV         22 /* no create table privilege */
   #define MRERQOP            23 /* invalid operator/function */
   #define MRERQATTR          24 /* incompatible attributes */
   #define MRERQPAT           25 /* invalid pattern */
   #define MRERQRNG           26 /* invalid range */
   #define MRERXCONS          27 /* invalid constant */
   #define MRERXCVT           28 /* invalid conversion */
   #define MRERXFUNC          29 /* invalid operator/function */
   #define MRERIEXIST         30 /* index already exists */
   #define MRERINEXIST        31 /* index does not exist */
   #define MRERICOMP          32 /* index name/definition mismatch */
   #define MRERCREATOR        33 /* invalid creator name */
   #define MRERCRPERMS        34 /* invalid create permissions */
   #define MRERDDEXIST        35 /* data dictionary already exists */
   #define MRERDBA            36 /* not the dba */
   #define MRERINPRIV         37 /* insufficient privileges */
   #define MRERDBACR          38 /* not the dba or creator */
   #define MRERRCNAME         39 /* invalid constraint name */
   #define MRERRCEXIST        40 /* constraint already exists */
   #define MRERRCNEXIST       41 /* constraint does not exist */
   #define MRERRCINSERT       42 /* insert constraint violation */
   #define MRERRCDELETE       43 /* delete constraint violation */
   #define MRERRCLKBUSY       44 /* cannot check constraint */
   #define MRERRCINCDTS       45 /* incompatible types in constraint */
   #define MRERRCOTABLE       46 /* cannot open table for constraint */
   #define MRERRCNATTR        47 /* invalid attribute in constraint */
   #define MRERNLOC           48 /* invalid location */
   #define MRERVWTWICE        49 /* table selected twice in view */
   #define MRERVWNONEQ        50 /* join condition without '=' */
   #define MRERVWOROP         51 /* OR conjunction in view */
   #define MRERVWNOTOP        52 /* NOT operator in view */
   #define MRERVWJOIN         53 /* insufficient join conditions */
   #define MRERVWKEY          54 /* insufficient keys in view */
   #define MRERVWREATTR       55 /* view attributes repeated/equated */
   #define MRERVWNONULL       56 /* cannot obtain 'not null' value */
   #define MRERVWUNIND        57 /* unique value unobtainable in view */
   #define MREREXPR           58 /* expression failure */
   #define MRERTRPROGRESS     59 /* transaction already in progress */
   #define MRERTRSTARTNOT     60 /* unable to start transaction */
   #define MRERTROFF          61 /* no transaction in progress */
   #define MRERTRINVSVP       62 /* invalid save point name */
   #define MRERTRSVPEXISTS    63 /* save point name already exists */
   #define MRERTRNOSVP        64 /* save point does not exist */
   #define MRERNUPDMODE       65 /* table opened in non-updatable mode */
   #define MRERSERVER         66 /* server not available */
   #define MRERANOTDTF        67 /* not a variable length attribute */
   #define MRERINOVRFL        68 /* index has no overflow file */
   #define MRERCRFL           69 /* cannot create data files */
   #define MRERCRFLACCESS     70 /* no access to create data files */
   #define MRERVWATTREX       71 /* too many attribute names specified */
   #define MRERGENDT          72 /* unknown generic type */
   #define MRERRECNO          73 /* invalid record number */
   #define MRERDT             74 /* invalid data type */
   #define MREREXDTPAR        75 /* too many parameters for the data type */
   #define MRERBADDTPAR       76 /* bad data type parameter */
   #define MRERATTRSPEC       77 /* attribute specification not allowed */
   #define MRERHAVBADA        78 /* disallowed attribute in having clause */
   #define MRERVWGRPGRP       79 /* no group by allowed on grouped view */
   #define MRERVWGRPHAV       80 /* no having allowed on grouped view */
   #define MRERVWGRPJOIN      81 /* no join allowed on a grouped view */
   #define MRERVWGRPQUAL      82 /* no qual allowed on grouped view */
   #define MRERVWORDERINT     83 /* invalid order by specification (integer) */
   #define MRERVWINSELHAV     84 /* invalid select list with having clause */
   #define MRERQNESTATTR      85 /* too many attributes in nested select */
   #define MRERVWAGGATTRX     86 /* no derived aggr attribute in expression */
   #define MRERVWAGGRHAV      87 /* no having allowed on aggregate view */
   #define MRERVWAGGRJOIN     88 /* no join allowed on a aggregate view */
   #define MRERVWAGGRQUAL     89 /* no qual allowed on aggregate view */
   #define MRERVWGRPAGGR      90 /* no aggr function allowed on grouped view */
   #define MRERVWINSELDIST    91 /* invalid select list with select distinct */
   #define MRERVWAGGATTRG     92 /* no derived aggr attribute in group by */
   #define MRERNOHASHREC      93 /* record not found in table */
   #define MREROPMODE         94 /* invalid table open mode */
   #define MRERVWORDERSEL     95 /* invalid order by specification (select) */
   #define MRERINVTXT         96 /* invalid char in the value for attribute */
   #define MRERDRIOATTR       97 /* direct I/O not supported for attribute */
   #define MRERDRIOSET        98 /* file redirection error */
   #define MRERCRSIZE         99 /* record size too large */
   #define MRERNLCOMP        100 /* null compile entry for the table */
   #define MRERNOCOMP        101 /* no compile entry for the table */
   #define MRERNVEW          102 /* expecting a view, got a table */
   #define MR_DB_ALREADY_LOCKED 103 /* the database has been already locked */
   #define MR_IN_ADM         104 /* the dba put the database down*/
   #define MRERDTER          105 /* Refer to error at DT level */
   #define MRERINVUREC       106 /* invalid record for update */
   #define MRERURECDEL       107 /* record for update has been deleted */
   #define MRERAGGRNORECS    108 /* no records to do aggregate */
   #define MRERNOCRSHM       109 /* cannot create shared memory */
   #define MRERNORMSHM       110 /* cannot remove shared memory */
   #define MREROUTERILL      111 /* Illegal outer join */
   #define MRERNOSHM         112 /* No shared memory available */
   #define MRERDRECDEL       113 /* deleted record for delete */
   #define MRERNONEXIST      114 /* no data file for '%s' */
   #define MRERNET           115 /* network error in file operation */
   #define MREROPEN          116 /* bad data file for '%s' */
   #define MRERFLOPMODE      117 /* invalid open mode '%c' */
   #define MRERSVPORT_BADID  118 /* invalid server port id */
   #define MRERSVPORT_INCOMPAT 119 /* incompatible server port id */
   #define MRERSVPORT_UNDEF  120 /* server port not defined */
   #define MREROPDICTMODE    121 /* invalid data dictionary open mode */
   #define MRERFULLBUSY      122 /* lock resource is full */
   #define MRERNOLKRESOURCE  123 /* cannot access lock resource */
   #define MRERBADRECORD     124     /* bad record retrieved */
   #define MRERBADDATARETR   125     /* from DT: bad var.len.val.retrieved*/
   #define MRERSORTLOCK      126 /* sort by error(locked) **WARNING */
   
   #define MRERMNAME         127 /* invalid module name */
   #define MRERMEXIST        128 /* module already exist */
   #define MRERMNEXIST       129 /* module does not exist */
   #define MRERLANGOPTION    130 /* invalid language option */
   #define MRERFNAME         131 /* invalid SQL-invoked routine name */
   #define MRERFMCLASS       132 /* there are multiple function
                                    classes for same routine */
   #define MRERFEXIST        133 /* SQL-invoked routine already exist */
   #define MRERFNEXIST       134 /* SQL-invoked routine not exist */ 
   #define MRERPARAMNAME     135 /* invalid parameter name */
   #define MRERPARAMEXIST    136 /* parameter already exist */
   #define MRERPARAMNEXIST   137 /* parameter does not exist */
   #define MRERPARAMNO       138 /* invalid parameter number */ 
   #define MRERQPARAM        139 /* incompatible parameter */
   #define MRERPARAMNUM      140 /* too many parameters */
   #define MRERPARAMNUM1     141 /* expecting one parameter */
   #define MRERPARAMNUM2     142 /* expecting two parameters */
   #define MRERPARAMB        143 /* parameter data type should 
                                    be generic boolean */  
   #define MRERPARAMNB       144 /* parameter data type should 
                                    be parametric data type */
   #define MRERRETB          145 /* return data type should be 
                                    generic boolean */
   #define MRERRETNB         146 /* return data type should be 
                                    parametric data type */
   #define MRERARETNB        147 /* aggregate function's return data type 
                                    should be parametric data type */
   #define MREREXTNAME       148 /* invalid external function name */
   #define MREREXTEXIST      149 /* external name already exist */
   #define MRERFILENEXIST    150   /* file doesn't exist */
   
   #define MRERTRNAME        151  /* invalid trigger name */
   #define MRERTREXIST       152 /* trigger already exist */
   #define MRERTRNEXIST      153 /* trigger does not exist */
   #define MRERMODWRAPCOMPFAIL 154 /* failed to compile wrapper for module */
   #define MRERDDCACHEFAIL   155 /* failed to modify DD_CACHE for module */
   #define MRERXSVFUNC       156 /* SQL-invoked routine '%s' is not 
                                    available on the client */
   #define MRERTRIGABORT     157 /* operation aborted by trigger */
   #define MRERXTRIGPROC     158 /* trigger procedure should have
                                    no parameter */
   #define MRERNOTRIGPROC    159 /* trigger procedure '%s' unavailable */
   #define MRERTRIG_OLD_NEW  160 /* attribute '%s' must be qualified 
                                    by OLD or NEW */
   #define MRERTRIGNESTED    161 /* nested queries are not allowed
                                    for triggers */
   #define MRERPARAMSTYLE    162 /* parameter style of SQL-invoked
                                    routine '%s' inconsistent */ 
   #define MRERMODWRAPGENFAIL 163 /* failed to generate wrapper for system */
   #define MRERNOATTR        164 /* no attributes left in table '%s */
   #define MRERRNGCONVT      165 /* cannot convert range check for 
                                    attribute '%s' */
   #define MRERCANTADDATTR   166 /* cannot add non-null attribute 
                                    to non-empty table */
   #define MRERDUPATTR       167 /* duplicate attribute '%s' */
   #define MRERFEWCONS       168 /* too few constants */
   #define MRERMANYCONS      169 /* too many constants */
   #define MRERWRONGCONS     170 /* wrong number of constants */
   #define MRERAINVEXPR      171 /* invalid expression for attribute '%s' */
   #define MRERSAMETAB       172 /* same table involved in select 
                                    and insert */
   #define MRERFEWSETATTR    173 /* too few SET attributes */
   #define MRERMANYSETATTR   174 /* too many SET attributes */
   #define MRERFEWATTRS      175 /* too few attributes in '%s' */
   #define MRERNOTNULLATTR   176 /* not-null attribute '%s' is not 
                                    included in attribute list */
   #define MRERINVATTR       177 /* invalid attribute '%s' for table '%s' */
   #define MRERINVIDXPARM    178 /* invalid index parameters (%s, %s)" */
   #define MRERNOPRIVCRVW    179 /* insufficient privileges to create view */
   #define MRERUNEQCONSTR    180 /* unequal number of attributes 
                                    in the constraint */
   #define MRERNOCONSTR      181 /* constraint '%s' does not exist */
   #define MRERNOIDX         182 /* index '%s' does not exist */
   #define MRERSYSTABLE      183 /* cannot perform %s operation on %s */
   #define MRERINVOPR        184 /* invalid operator '%s' */
   #define MREREXPRPROB      185 /* expression cannot be evaluated 
                                    or out of range */
   #define MRERUPDMOD        186 /* failed to update module '%s' 
                                    (unable to resolve symbol) */ 
   #define MRERCOPYRL        187 /* failed to copy file from server 
                                    to client */
   #define MRERCOPYLR        188 /* failed to copy file from client 
                                    to server */
   #define MRERINVCALLEXPR   189 /* invalid call expression, output 
                                    is not bound with a variable */
   /* next number is 190 */



2.6 Empress File Quotas

If you need to open your own files in your program and cannot do so because Empress has used all available file descriptors, you will have to limit the number of files Empress will attempt to open. This can be done by setting the Empress system variable MSFILESOPEN in the operating system. For example, to limit the number of files Empress will attempt to open to 10:

Not that, this will not prevent Empress from accessing more than 10 files. Empress will close the least-recently used file before opening another file, if the quota is reached. If the file that was closed by Empress is accessed again, Empress will automatically re-open it. Empress keeps track of these files internally and the closing and re-opening of files are transparent to the user.

For details on setting Empress system variables, refer to the Setting Variables in the Empress SQL: User's Guide manual.



2.7 Naming Conventions

The mr routines have been named in a regular manner to suggest their function. Each name begins with "mr". Most then have a letter suggesting a generic function, such as "q" for the routines dealing with qualifications, or a full word, such as "get" for the routines that find attribute values. All the routines which have a "t" following the "mr" return some sort of value which may be tested to see if the routine succeeded or failed; the other routines terminate the calling program if they fail.

The following is a classification and list of all the mr routines. Manual pages with detailed specifications for each of these routines may be found in Manual Pages, and should be referred to when writing programs.

The following table lists the routines used to open and close tables:

Table 2-3: Open Routines

Name Description
mropen Open a table for use with the mr routines, with locking as prescribed in the data dictionary; terminate calling program on failure.
mrtopen Open a table; do not terminate on failure.
mropdict Open the data dictionary; terminate calling program on failure.
mrtopdict Open the data dictionary; do not terminate calling program on failure.
mrclose Close a table after use with the mr routines and unlock it if locked.
mrcldict Close the data dictionary.
mrqdb Check if a directory is a database.

The following table lists the routines used to control locking:

Table 2-4: Lock Routines

Name Description
mrlktab Lock table at table level.
mrlkrec Lock a record.
mrultab Remove a table level lock.
mrulrec Remove the lock created by mrlkrec.

The following table lists the routines used to allocate and deallocate memory:

Table 2-5: Allocate Space Routines

Name Description
mrmkrec Allocate space to store one record.
mrfrrec Free space allocated by mrmkrec.
mrspv Allocate space to store an attribute value.
mrfree Free space allocated by mrspv.

The following table lists the routines used to manipulate attribute descriptors:

Table 2-6: Attribute Descriptor Routines

Name Description
mrngeta Get a descriptor for a named attribute.
mrigeta Get a descriptor for a numbered attribute.
mrganame Find an attribute name given its descriptor.

The following table lists the routines used to assign values to records:

Table 2-7: Filling Records Routines

Name Description
mrputvs Assign a value (external format) to an attribute in a record; do not terminate on failure.
mrputvi Assign an integer to an attribute in a record; do not terminate on failure.
mrputi Assign a value (internal format) to an attribute in a record; do not terminate on failure.
mrmptvs Assign a value (external format) to an attribute in a record; terminate on failure.
mrmptvi Assign an integer to an attribute in a record; terminate on failure.
mrsetnv Assign a NULL value to an attribute in a record.
mrsetnr Assign a NULL values to all attributes in a record.

The following table lists the routines used to insert records into a table:

Table 2-8: Insert Routines

Name Description
mradd Insert a record; terminate on failure.
mrtadd Insert a record; do not terminate on failure.
mraddend Clean up after inserting records into a table.

The following table lists the routines used to delete records from a table:

Table 2-9: Delete Routines

Name Description
mrdel Delete a record; terminate on failure.
mrtdel Delete a record; do not terminate on failure.
mrdelend Clean up after deleting records from a table.

The following table lists the routines used to update records in a table:

Table 2-10: Update Routines

Name Description
mrcopyr Copy attribute values from one record to another.
mrput Update a record; terminate on failure.
mrtput Update a record; do not terminate on failure.

The following table lists the routines used to initialize retrieval of values from a table:

Table 2-11: Initialize Retrieval Routines

Name Description
mrgetbegin Associate qualifications with records for retrievals; terminate on failure.
mrtgtbegin Associate qualifications with records for retrievals; do not terminate on failure.
mrsrtbegin Associate qualifications with records for sorted retrievals; terminate on failure.
mrtsrbegin Associate qualifications with records for sorted retrievals; do not terminate on failure.

The following table lists the routines used to retrieve values from a table:

Table 2-12: Retrieval Routines

Name Description
mrget Retrieve a record from a table.
mrtget Retrieve a record, report if record locked.
mrreget Try again for the next record.
mrprev Retrieve the previous record.
mrtprev Retrieve the previous record, report if locked.
mrreprev Try again for the previous record.
mrgetrec Get a record referred to by a previously-found pointer.
mrgetend Clean up after retrieving records from a table.
mrcontrol Specify how many bytes of a particular bulk attribute value will actually be retrieved from a table.
mrcopyv Assign the value (external format) of an attribute to an allocated space.
mrcopyi Assign the value (internal format) of an attribute to a variable.
mrgetvs Retrieve an attribute value (external format).
mrgetvi Retrieve an attribute value (as an integer).
mrgeti Retrieve an attribute value (internal format).
mrgetptr Find a pointer to a given record for later use.
mrgfunc Find COUNT, MAX, MIN, SUM, or AVG of an attribute; terminate on failure.
mrtgfunc Find COUNT, MAX, MIN, SUM, or AVG of an attribute; do not terminate on failure.

The following table lists the routines used to perform comparisons between attribute values:

Table 2-13: Compare Routines

Name Description
mrcompare Find whether a variable is equal to, less than, or greater than an attribute value.
mrnullr Find whether an entire record is NULL.
mrnullv Find whether an attribute value is NULL.

The following table lists the routines used to convert values between different data formats:

Table 2-14: Input Conversion Routines

Name Description
mrcvt Convert a value from external format to file format. (Shared buffer with other mr routines.)
mrcvtin Convert a value from internal format to file format. (Shared buffer with other mr routines.)
mrcvtv Convert a value from external format to file format. (Shared buffer with mrcvti.)
mrcvtv2 Convert a value from external format to file format. (Shared buffer with mrcvti2.)
mrcvti Convert a value from internal format to file format. (Shared buffer with mrcvtv.)
mrcvti2 Convert a value from internal format to file format. (Shared buffer with mrcvtv2.)

The following table lists the routines used to compare attributes:

Table 2-15: Qualification Routines

Name Description
mrqcon Compare an attribute value with a constant; terminate on failure.
mrtqcon Compare an attribute value with a constant; do not terminate on failure.
mrqrng Compare an attribute value with a given range; terminate on failure.
mrtqrng Compare an attribute value with a given range; do not terminate on failure.
mrqatr Compare two attribute values; terminate on failure.
mrtqatr Compare two attribute values; do not terminate on failure.
mrqmch Match an attribute value with a constant; terminate on failure.
mrtqmch Match an attribute value with a constant; do not terminate on failure.
mrqnul Compare an attribute value with NULL; terminate on failure.
mrtqnul Compare an attribute value with NULL; do not terminate on failure.
mrqseq See if an attribute is equal to a string; terminate on failure.
mrqieq See if an attribute is equal to an integer; terminate on failure.
mrqand Perform an AND on any two of the above comparisons.
mrqor Perform an OR on any two of the above comparisons.
mrqnot Perform a NOT on any of the above comparisons.
mrqlst Qualify records in the given list of previously found pointers to records.

The following table lists the routines used to control transactions:

Table 2-16: Transaction Routines

Name Description
mrtrstart Start a transaction.
mrtrcancel Cancel a transaction.
mrtrcommit Commit a transaction.
mrtrsave Set save point in transaction.
mrtrrollback Roll back to save point.

The following table lists the routines used to build expressions:

Table 2-17: Expression Routines

Name Description
mrebegin Start building expression.
mreend Finish building expression.
mreabort Abort building expression.
mrqexpr Put expression in qualification.
mrerun Run expression and return result.
mrefree Free expression descriptor.
mrerecattr Add an attribute operand.
mrecons Add a constant operand.
mreicvar Associate a control variable with the most recent variable.
mreivar Add a variable operand.
mrecvarg Add a type conversion operator.
mrefunc Add a function or operator.
mrenull Add a NULL operator.
mrgdtpar Get a data type descriptor.

The following table lists the data streaming routines used for BULK and TEXT datatypes:

Table 2-18: Data Streaming Routines

Name Description
mrbuktxtcrt Create a user specified space in an existing .dtf file (BULK and TEXT data overflow file).
mrsubbegin Initiate the start of data streaming update operation.
mrsubend Indicate the end of data streaming update operation.
mrsubputi Perform a data segment update for BULK or TEXT data type.
mrsubgeti Retrieve a segment of data from a BULK or TEXT attribute.
mrbuktxtlen Get the length of BULK or TEXT data.

The following table lists the routines used to handle errors:

Table 2-19: Error Handling Routines

Name Description
mrprterr Print a suitable message if one of the mr routines fails; terminate calling program.
mrerrmsg Retrieve last error message.



2.8 Empress Internal Procedure Names

When writing application programs, if one of your own procedures has the same name as one of the Empress internal procedures, problems occur (e.g., complaints from the loader about multiply defined routines). If you are having problems with one of your routines and its name begins with one of the prefixes listed below, try changing its name.

To help spot this problem, the prefixes used in naming the Empress internal procedures are listed below (This is not a complete list and it may change from version to version of Empress.):

   addr         ap*
   byte
   cpbytes*     cv* 
   date*        day*       dt* 
   er*          ewrite*    exit*     extsrt* 
   fl*          fm*        fork* 
   gdat*        gdec*      gflt*     gint* 
   int
   ll* 
   main         match*     mem*      month*   mp*    mr*     ms*
   msbool       mw*        mx* 
   of* 
   prog* 
   ql* 
   ran* 
   sc*          sep*       sfmt       sig*     sm*    sp*     str* 
   taddr        time*      tty*     
   ufx* 
   varg* 
   wkday*       word        ww* 
   xf* 
   year*



2.9 General Overview of the mr Routines

The following description covers the general use of the mr routines. Many of the routines mentioned below have counterparts which return error codes on failure rather than terminating the calling program. There are, in addition, a number of specialized retrieval and qualification routines which are not included in this overview.

Given a database directory, a table within it, and a code for the required open mode, mropen opens the table, sets it up for locking at the level indicated in the data dictionary, and returns a pointer to a table_descriptor. Once a table has been opened, a storage structure for a record of that table may be allocated by mrmkrec, which returns a pointer to a record structure. Various operations may now be performed on the table. When all operations on a table are finished, it should be closed using mrclose.

If any operations are to be performed on single attributes, mrigeta or mrngeta must be used to obtain an attribute_descriptor for the given attribute (referred to by number or by name, respectively). The name of an attribute may be obtained if there is a descriptor for it using mrganame.

Record retrievals are initialized by calling mrgetbegin. This routine associates any previously defined retrieval qualification (an internal representation of a WHERE clause) with the records of the table. mrgetbegin must be called even if there is no qualification. If the output is to be sorted, use mrsrtbegin instead of mrgetbegin.

Qualifications are created by calls to mrqcon, mrqrng, mrqatr, mrqmch, or mrqnul. These routines are used to compare an attribute value with a constant, a range of values, or another attribute value, and perform a match with a constant, or a comparison with NULL, respectively. If the values to be used in these comparisons are in external format, they must first be converted to file format by the routine mrcvt. Complex qualifications are produced by using the descriptors returned by simple qualifications as arguments to mrqand, mrqor, or mrqnot, which perform AND, OR, and NOT functions, respectively.

Retrievals are accomplished by repeated calls to mrget and mrprev. Each call to mrget (or mrprev) stores the record values in internal form in the specified record structure. If a record is temporarily inaccessible because someone else has locked it, mrreget (or mrreprev) may be used to make repeated attempts to access it. Use mrspv to allocate space to store an attribute value, and use mrcopyv to assign the value to the space allocated. (For text data types, mrgetvs must be used instead of mrcopyv.) This produces an external character string representation of the data, which may be examined and manipulated by the application program.

If you wish to use the internal format of attribute values, the routine mrcopyi is used to retrieve attribute values instead of mrcopyv. Note that using this routine results in machine-dependent code.

The count, maximum value, minimum value, sum, or average of an attribute may be found by mrgfunc.

mrfree frees the space allocated by mrspv.

If you simply wish to know if the value of a variable is equal to, greater than, or less than an attribute, the routine mrcompare may be used. Similarly, you may check whether an entire record is NULL with mrnullr, or if a single attribute value is NULL with mrnullv.

To create a new record, attribute values are added to a record structure using mrputvs (or mrsetnv to set an attribute value to NULL). mrputi may be used instead of mrputvs if you are working with internal attribute formats instead of external ones. The entire record may be explicitly set to NULL using mrsetnr. The record is then added to the table by a call to mradd. The routine mraddend cleans up after records have been added. If there is a possibility that the new record may not be allowed as input (such as occurs with duplicate values for a uniquely indexed attribute or when record-level locking is in force), mrtadd should be used to add the record, as it indicates whether the addition was successful or not.

Records are deleted using mrdel or mrtdel, and mrdelend should be called to do cleaning up after deletions.

Updates are done using mrmkrec to create a new record, mrcopyr to copy the old record into it, mrputvs to change attribute values in the new record, and mrput to replace the old record with the new one.

The space allocated to record structures should be freed using mrfrrec. Note that it is good practice to free allocated space once it is no longer needed; otherwise, the application may run out of space.

The entire data dictionary for a database may be opened by mropdict, and closed again with mrcldict.

A transaction may be started by mrtrstart, and committed or cancelled by mrtrcommit or mrtrcancel, respectively. A save point in a transaction is set with mrtrsave and a transaction is rolled back to a save point with mrtrrollback.

To build expressions, start with a call to mrebegin and end with a call to mreend. An expression is directly evaluated with mrerun and converted to a qualification with mrqexpr. After an expression is evaluated its descriptor is freed with mrefree. The routine mreabort is used to abort building an expression if an error condition is detected. Expressions are built using mrecons, mreivar, and mrerecattr to add constants, variables, and attributes, respectively, as arguments to the next function, and mrefunc to add a function. The routine mrenull tests whether the last argument is NULL, mrgdtpar gets a data type descriptor, and mrecvarg converts the expression type to a specified data type.



2.10 Database, Table, and Attribute Names

Most arguments to the mr routines are used to specify database, table, or attribute names, or data values. Generally, these arguments are character strings.

When two or more opened databases have tables with the same name, the database name and a colon are prefixed to the table name, thus:

   database:table

Attribute names can be similarly qualified by prefixing a table name and a period to the attribute name. This may be further qualified by a database name as before. Hence, acceptable forms of attribute names are:

   attribute
   table.attribute
   database:table.attribute

It is good practice to qualify attribute names with their table names as a matter of course, since errors resulting from dealing with an attribute in the wrong table may be quite difficult to spot when debugging code. This also guards against confusion resulting from later attribute name changes in the tables used by the application.



2.11 Error Messages

There are five major types of errors when using mr routines:

All have the following format:

   *** Error Type *** explanation_of_error

Program Bug

A program bug error message indicates that there is a programming error in the application program. It usually arises when passing a procedure with the wrong parameters. For example, attempting to insert data into a table which was opened in read-only mode, or specifying old and new records from different tables in an update, will cause program bug errors.

Space Problem

This kind of error simply indicates that the program has run out of space. Be sure to free the space allocated for record_descriptors, attribute_descriptors, etc., as soon as they are no longer needed, or a space problem error may arise. Attempting to create a table with very large numbers of attributes may also give rise to a space problem error.

User Error

This kind of error is usually caused by data input while running the application. It may be the result of passing incorrect table or attribute names to a procedure. Incorrect names which are written into an application program are usually easy to find and fix. For names entered during execution, mrtopen can be used to check table names, and mrngeta to check attribute names.

Database Problem

This error is very serious, and occurs when the database is found to be corrupted.

File Problem

This error occurs when the mr routines cannot access a file which they should be able to access. It is generally a serious problem, and may indicate a corrupted database.



2.12 Locking

If locking is specified for a table in the data dictionary of the database, a table or record may be locked in read or update mode. Note that if the appropriate level of locking is not specified in the data dictionary, calls to routines to lock a table or record will have no effect.

Some applications, especially those involving a read-only database or a "single-user" database, do not require locks. These applications are better implemented without using locks, since employing the locking mechanism introduces complexities and is hence more error-prone. The database administrator should set guidelines for the use of locks, and set the default locking on tables accordingly. For a discussion on locking, see the Empress SQL: Reference manual under the LOCK LEVEL command.

Locking a table or record in read mode means that others may access it, provided they also access it in read mode. Thus anyone who wishes to update this table or record will be prevented from accessing it until everyone is finished with the table.

Locking a table or record in update mode means no one else may access it for reading or updating. This can cause a bottleneck if one person keeps the table or record locked for a long period of time, or if a table or record is locked and never unlocked.

A table can be opened in read, update, or deferred mode. Opening a table in read mode places read locks on the table. Opening a table in update mode places update locks on the table. Opening a table in deferred mode places read locks on the table initially, but these locks are exchanged for update locks when the table is written to.

The utility program msclrlk and empadm may be used to clean up any hanging locks on a database. This is particularly useful when debugging programs with MSDEBUG set to abort, because if a program core dumps you will almost certainly have left-over locks which should be removed.



2.13 Portability

Executable programs containing calls to mx/mr routines can be moved across machines running:

  1. Compatible Operating System
  2. the Same version of Empress
If any of the above conditions are not met, programs should be recompiled on the target machine.