# Chapter 2: mr ルーチン

## 2.1 はじめに

一般的に、mrルーチンによって、テーブルのオープン、レコードの追加、削除、検索、更新が行なえます。すべての操作は 一つのレコードに対して実行可能です。以下に示す、6つのデータポインタがあります。

1. オープンされたテーブルを指す、テーブル記述子（teble_descriptors)。

2. フィールドを指す、フィールド記述子（attribute_descriptors)。

3. レコードを指す、レコード記述子（record_descriptors）。

4. フィールドまたはレコードと、条件を関連付ける、条件記述子（qualification_descriptors）。

5. テーブルと条件を関連付ける、検索記述子（retrieval_descriptors）。

6. フィールド値の、外部フォーマットに一致する文字列（strings）。いくつかのフィールド値の、フォーマットを以下の 章で解説します。

最初の5つのデータポインタは、"addr"として宣言され、6番目の文字列は、"char *"として宣言しなくてはなりません。 テーブル、レコード、フィールド、条件の各記述子は、Emppress内部構造体へのポインタです。"addr"データタイプは、 "char *"として定義されていますが、これらのポインタは、文字列ではないので、そのように使用してはなりません。 addrデータタイプは、この連想子として使用されています。

## 2.2 mrルーチンによるアクセス

### 2.2.1 ヘッダーファイルmscc.h

ヘッダーファイルmscc.hは、mrルーチンを使用するプログラムの先頭で、インクルードしなくてはなりません。ここには すべてのmr関数の定義と、多数のデータタイプ(addr、booleanなど）と定数の定義が含まれています。 mscc.hは、標準I/Oライブラリをインクルードしているので、プログラム中で、このライブラリをインクルードする必要は ありません。mscc.hファイルの内容を、以下に示します。

mscc.hファイルは、バージョンによって内容が違います。正確なファイルの内容は、$EMPRESSPATH/includeディレクトリにあるファイルを参照してください。

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

       #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 初期化とクリーンアップ

Empress mrルーチンを使用した、プログラムの作成には、2つの方法があります。

1. 通常のmainプロシージャを、msmainとします。これは必要な初期化を行い、mainプロシージャをインクルード します。また、通常通り、パラメータargcとargvを使用できます。 同様に、通常のexitプロシージャをmsexitにします。

2. mainプロシージャを書くことも可能です。そのためには、msinitを呼び出して初期化し、msexitを呼び出して クリーンアップします。

msclean関数は、プログラム終了前に、呼び出され実行されるプロシージャを、スタックに配置します。

### 2.2.3 コンパイルとリンク

mrルーチンを使用したプログラムは、ccではなくempccまたはempc++で、コンパイルされる必要があります。この結果、 コンパイルで、Empress関数のライブラリが、確実にリンクされます。この他はccと同様に機能します。

mscall文も、empccまたはempc++によって、コンパイルされるプログラムで使用できます。例えば、アプリケーション プログラム内で、新しいテーブルを作成する、最も簡単な方法は、mscall文を使用することです。

## 2.3 内部、外部、ファイルフォーマット

ここでは、フィールド値の内部、外部、ファイルフォーマットについて解説します。外部フォーマットは、クエリーのSELECT コマンドによって、表示されるフォーマットです。外部フォーマットの値は、文字列です。

内部フォーマットは、Empressで処理されるフォーマットです。これは外部フォーマットと、必ずしも一致しません。例えば date(1)タイプの値は、"20 April 2003"として処理されているわけではありません。またDOLLARタイプでは、ドル記号、カンマ、ピリオドを 持った値が、処理されているわけではありません。

ファイルフォーマットは、Empressによりディスク上に、値が保存される場合のフォーマットです。アプリケーションプログラムで 、ファイルフォーマットを、直接検索することはありません。

フィールド値は、通常は外部フォーマットで検索されますが、integer値または内部フォーマット値を、直接検索することも 可能です。フィールドへの、値の割り当ては、通常は外部フォーマットまたはinteger値で行いますが、内部フォーマットで 、直接割り当てることも可能です。

外部フォーマットで、検索された値の算術を行なう場合には、sscanf()やatof()を使用して、文字列から数値に変換する必要 があります。またドル記号、アスタリスクなどは、変換前に、DOLLAR値から削除しなければなりません。これを実行する方法 はdollcvtであり、3章で解説します。

BULKデータ値は、他のタイプとは異なった処理となります。外部フォーマットで、Bulk値を出力するには、バイトを通常 必要としない、16進文字に変換します。Bulkデータは、mrgetiを用いて内部フォーマットで取得できます。この関数は Bulkデータの検索用に、特に意図して作成されたものですが、他の内部フォーマットを取得するためにも、使用することが 可能です。次に章のサンプルプログラム、voice.cで内部フォーマットのBulk値を取得する、mrgetiの使用方法を解説して います。

## 2.4 データタイプ

Empressデータタイプ（MSデータタイプ）とC言語データタイプは、通常（マシンのアーキテクチャに従って）、以下のように 対応します。 データベースからの検索値を、C変数に格納する場合には、対応した適切なタイプでなければなりません。

Table 2-1 MSデータタイプに対応するC言語データタイプ

MSデータタイプ | Cデータタイプ
`CHAR` `CHARACTER` | char[](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[]` (EOSで終了)
`BULK` | `gen_binary*`
`DECIMAL` `DEC` | `unsigned char[]`
`TIME` | `gen_date`
`NLSCHAR` `NLSCHARACTER` | `char[]` (EOSで終了)
`NLSTEXT` | `char[]` (EOSで終了)
`MICROTIMESTAMP` | `gen_date`

Table 2-2 汎用データタイプに対応するC言語データタイプ

汎用データタイプ | Cデータタイプ
`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 エラーハンドリング

テーブルに、レコードレベルのロックが設定されていて、mrルーチンから、アクセスするレコードがロックされている場合、 あるいは、テーブルに格納しようとしているデータが、範囲チェックや重複制限インデックスのために、認められない場合、 あるいは、不適切なデータが受け渡された場合など、mrルーチンが、正しく実行を完了できない場合があります。

mrルーチンが失敗した場合に、呼出しプログラムを終了するか、しないかは関数によって異なります。関数の、成功あるいは 失敗を示す、フラグを返す関数は、他の方法で指定しない限り、失敗した場合には終了しません。フラグを返さない関数は、 失敗した場合に終了します。操作は、失敗時に終了する関数と、しない関数の2つを使用している場合が、あることに注意 してください。

失敗した場合でも、終了しない関数では、mroperr変数に、mrerrno.hファイルで定義されている、エラー変数MERE....の いづれかがセットされます。mroperr変数を参照する事により、失敗した原因や理由を取得することができ、アプリケーションを 制御することが可能となります。

mrerrno.hファイルの内容を、以下に示します。尚、この内容はバージョンにより違います。正確な内容は、 $EMPRESSPATH/include/usrmrディレクトリ配下にある、ファイルを参照してください。

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

       #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ファイル割当て

プログラム内で、ファイルをオープンする必要がある場合、Empressがすべての使用可能なファイルをオープンしていて 実行できないのであれば、Empressによって、オープンされるファイルの数を制限する必要があります。 これは、オペレーティングシステムに、Empressのシステム変数MSFILESOPENを、設定することで実行できます。 例えば、Empressがオープンできるファイル数を、10に設定する場合を以下に示します。

- UNIX/LINUX Cシェルの場合。

         setenv MSFILESOPEN 10

- UNIX/LINUX Bシェルの場合。

         MSFILESOPEN = 10
         export MSFILESOPEN

- Windowsの場合。

         set MSFILESOPEN = 10

これによって、Empressが10ファイルを越えたアクセスが、できないというわけではありません。 制限の10に到達した場合、Empressは、新しいファイルをオープンする前に、アクセスされていない、古いファイルをクローズ します。Empressによってクローズされたファイルは、必要に応じてアクセス時にオープンされます。Empressはファイルの 内容を内部に保存します。よって、クローズされたり、再オープンされたかはユーザには、わかりません

詳細は、Empress SQL: User's GuideのSetting Variables を参照してください。

## 2.7 名前付け規約

mrルーチンの、それぞれの関数名は規則的な方法で、命名されています。個々の関数名は、"mr"で始まります。 次に、機能を表す1文字が付けられます。例えば、条件を処理する関数であれば、"q"が付けられます。 そして、また次には、処理を表す文字、例えば検索であれば"get"が付けられます。 "mr"の次に、"t"が入る関数は、関数の失敗、成功を通知すつ値を返します。"t"が入らない関数は、失敗したら 呼出しプログラムは、終了します。

すべてのmrルーチンの分類と、概要を以下に示します。個々の関数の詳細な仕様は、このマニュアルの最後に記載 されています。プログラム作成時に参照してください。

以下に、テーブルのオープンとクローズで使用される関数を示します。

Table 2-3: オープン関数

名前 | 概要
`mropen` | データディクショナリーで指定されたロックを伴い、テーブルをオープンします。 失敗時には、呼出しプログラムを終了します。
`mrtopen` | テーブルをオープンします。失敗時には、呼出しプログラムを終了しません。
`mropdict` | データディクショナリーの、全テーブルをオープンします。失敗時には、呼出しプログラムを終了します。
`mrtopdict` | データディクショナリーの、全テーブルをオープンします。 失敗時には、呼出しプログラムを終了しません。
`mrclose` | テーブルをクローズし、ロックを解除します。
`mrcldict` | データディクショナリーをクローズします。
`mrqdb` | ディレクトリーが、データベースであるかチェックします。

以下に、ロックで使用される関数を示します。

Table 2-4: ロック関数

名前 | 概要
`mrlktab` | テーブルレベルのロックを設定します。
`mrlkrec` | レコードにロックを設定します。
`mrultab` | テーブルレベルのロックを解除します。
`mrulrec` | レコードのロックを解除します。

以下に、メモリの確保と解放で使用される関数を示します。

Table 2-5: スペース確保関数

名前 | 概要
`mrmkrec` | 1つのレコードを保存するためのスペースを確保します。
`mrfrrec` | mrmkrecで確保したスペースを開放します。
`mrspv` | 1つのフィールド値を保存するためにスペースを確保します。
`mrfree` | mrspvで確保したスペースを開放します。

以下に、フィールド記述子の操作で使用する関数を示します。

Table 2-6: フィールド記述子関数

名前 | 概要
`mrngeta` | フィールド名から記述子を取得します。
`mrigeta` | フィールド番号から記述子を取得します。
`mrganame` | 記述子からフィールド名をします。

以下に、レコードに値を割り当てに使用する関数を示します。

Table 2-7: レコード割当て関数

名前 | 概要
`mrputvs` | レコード内のフィールドに、値（外部フォーマット）を割当てます。失敗しても終了しません。
`mrputvi` | レコード内のフィールドに、integer値を割当てます。失敗しても終了しません。
`mrputi` | レコード内のフィールドに、値（内部フォーマット）を割当てます。失敗しても終了しません。
`mrmptvs` | レコード内のフィールドに、値（外部フォーマット）を割当てます。失敗したら終了します。
`mrmptvi` | レコード内のフィールドに、integer値を割当てます。
`mrsetnv` | レコード内のフィールドに、NULL値を割当てます。
`mrsetnr` | レコード内のすべてのフィールドに、NULL値を割当てます。

以下に、テーブル内にレコードを挿入するために使用する関数を示します。

Table 2-8: 挿入関数

名前 | 概要
`mradd` | レコードを挿入します。失敗時に終了します。
`mrtadd` | レコードを挿入します。失敗時に終了しません。
`mraddend` | テーブルへの、レコード挿入後のクリーンアップを行います。

以下に、レコードを削除する場合に使用する関数を示します。

Table 2-9: 削除関数

名前 | 概要
`mrdel` | レコードを削除します。失敗時に終了します。
`mrtdel` | レコードを削除します。失敗時に終了しません。
`mrdelend` | レコードを削除した後の、クリーンアップを行ないます。

以下に、レコードを更新する場合に使用する関数を示します。

Table 2-10: 更新関数

名前 | 概要
`mrcopyr` | フィールド値を、レコードから別のレコードにコピーします。
`mrput` | レコードを更新します。失敗時に終了します。
`mrtput` | レコードを更新します。失敗時に終了しません。

以下に、検索に初期化を行なう場合に使用する関数を示します。

Table 2-11: 初期化関数

名前 | 概要
`mrgetbegin` | 検索のために、条件とレコードを関連付けます。失敗時に終了します。
`mrtgtbegin` | 検索のために、条件とレコードを関連付けます。失敗時に終了しません。
`mrsrtbegin` | ソート検索のために、条件とレコードを関連付けます。失敗時に終了します。
`mrtsrbegin` | ソート検索のために、条件とレコードを関連付けます。失敗時に終了しません。

以下に、検索のために使用される関数を示します。

Table 2-12: 検索関数

名前 | 概要
`mrget` | レコードを検索します。
`mrtget` | レコードを検索します。ロックされていれば通知します。
`mrreget` | レコードを再検索します。
`mrprev` | 前のレコードを検索します。
`mrtprev` | 前のレコードを検索します。ロックされていれば通知します。
`mrreprev` | 前のレコードを再検索します。
`mrgetrec` | 以前に検索されたポインタが、参照するレコードを取得します。
`mrgetend` | 検索後のクリーンアップを行ないます。
`mrcontrol` | Bulk値から、検索されるバイト数を指定します。
`mrcopyv` | フィールド値（外部フォーマット）を、割付けられたスペースに割当てます。
`mrcopyi` | フィールド値（内部フォーマット）を、変数に割当てます。
`mrgetvs` | フィールド値（外部フォーマット）を取得します。
`mrgetvi` | フィールド値（integer値）を取得します。
`mrgeti` | フィールド値（内部フォーマット）を取得します。
`mrgetptr` | 後で使用するために、指定レコードへのポインタを取得します。
`mrgfunc` | フィールドに対し、集計関数（count,max,min,avg,sum)の結果を取得します。失敗時に終了します。
`mrtgfunc` | フィールドに対し、集計関数（count,max,min,avg,sum)の結果を取得します。失敗時に終了しません。

以下に、フィールド値の比較を実行する場合に使用する関数を示します。

Table 2-13: 比較関数

名前 | 概要
`mrcompare` | 変数が、フィールド値に等しいか、小さいか、大きいか調べます。
`mrnullr` | レコード全体が、NULLであるか調べます。
`mrnullv` | フィールド値が、NULLであるか調べます。

以下に、異なるデータタイプ間で、値の変換に使用する関数を示します。

Table 2-14: 入力変換関数

名前 | 概要
`mrcvt` | 外部フォーマットから、ファイルフォーマットへ値を変換します。（他の関数との共有バッファ使用）
`mrcvtin` | 内部フォーマットから、ファイルフォーマットへ値を変換します。（他の関数との共有バッファ使用）
`mrcvtv` | 外部フォーマットから、ファイルフォーマットへ値を変換します。（mrcvtiとの共有バッファ使用）
`mrcvtv2` | 外部フォーマットから、ファイルフォーマットへ値を変換します。（mrcvti2との共有バッファ使用）
`mrcvti` | 内部フォーマットから、ファイルフォーマットへ値を変換します。（mrcvtvとの共有バッファ使用）
`mrcvti2` | 内部フォーマットから、ファイルフォーマットへ値を変換します。（mrcvtv2との共有バッファ使用）

以下に、フィールドを比較する場合に使用する関数を示します。

Table 2-15: 条件関数

名前 | 概要
`mrqcon` | フィールド値を定数と比較します。失敗時には終了します。
`mrtqcon` | フィールド値を定数と比較します。失敗時には終了しません。
`mrqrng` | フィールド値を指定範囲と比較します。失敗時には終了します。
`mrtqrng` | フィールド値を指定範囲と比較します。失敗時には終了しません。
`mrqatr` | 2つのフィールド値を比較します。失敗時には終了します。
`mrtqatr` | 2つのフィールド値を比較します。失敗時には終了しません。
`mrqmch` | フィールド値を定数とマッチングします。失敗時には終了します。
`mrtqmch` | フィールド値を定数とマッチングします。失敗時には終了しません。
`mrqnul` | フィールド値をNULLと比較します。失敗時には終了します。
`mrtqnul` | フィールド値をNULLと比較します。失敗時には終了しません。
`mrqseq` | フィールド値が文字列と等しいか調べます。失敗時には終了します。
`mrqieq` | フィールド値が文字列と等しいか調べます。失敗時には終了しません。
`mrqand` | 2つの条件をAND結合します。
`mrqor` | 2つの条件をOR結合します。
`mrqnot` | 比較条件を否定します。
`mrqlst` | 以前に取得した、レコードへのポインタのリストで、レコードを制限します。

以下に、トランザクションを制御するのに使用する関数を示します。

Table 2-16: トランザクション関数

名前 | 概要
`mrtrstart` | トランザクションを開始します。
`mrtrcancel` | トランザクションを取り消します。
`mrtrcommit` | トランザクションを確定します。
`mrtrsave` | トランザクション内にセーブポイントを設定します。
`mrtrrollback` | セーブポイントまでロールバックします。

以下に、表現を構築する場合に使用する関数を示します。

Table 2-17: 表現関数

名前 | 概要
`mrebegin` | 表現式の構築を開始します。
`mreend` | 表現式の構築を完了します。
`mreabort` | 表現式の構築を中止します。
`mrqexpr` | 表現式を制限に配置します。
`mrerun` | 表現式を実行し、結果を取得します。
`mrefree` | 表現式の記述子を解放します。
`mrerecattr` | フィールドオペランドを付加します。
`mrecons` | 定数オペランドを付加します。
`mreicvar` | 最新の変数を、制御変数に関連付けます。
`mreivar` | 変数オペランドを付加します。
`mrecvarg` | タイプ変換演算子を付加します。
`mrefunc` | 関数または演算子を付加します。
`mrenull` | NULL演算子を付加します。
`mrgdtpar` | データタイプ記述子を調べます。

以下に、BULKとTEXTデータタイプ用の、データストリーミング関数を示します。

Table 2-18: データストリーミング関数

名前 | 概要
`mrbuktxtcrt` | .dtfファイル（BULK、TEXTのオーバーフローファイル）中に、指定されたスペースを作成します。
`mrsubbegin` | データストリーミングの更新操作を開始します。
`mrsubend` | データストリーミングの更新操作を終了します。
`mrsubputi` | BULK、TEXTのデータタイプに対して、データセグメントの更新を実行します。
`mrsubgeti` | BULK、TEXTのデータセグメントを検索します。
`mrbuktxtlen` | BULK、TEXTのデータ長を取得します。

以下に、エラーハンドリングに使用する関数を示します。

Table 2-19: エラーハンドリング関数

名前 | 概要
`mrprterr` | mr関数が失敗した場合に、適切なエラーメッセージを表示します。呼出しプログラムを終了します。
`mrerrmsg` | 最終のエラーメッセージを取得します。

## 2.8 Empress内部関数名

アプリケーションプログラムの作成時に、ユーザ関数名が、Empressの内部関数名と 同一の場合、リンク時にエラーが発生します。関数名で障害が発生した場合、接頭辞をチェックして、必要に応じて変更してください。

この障害を防ぐために、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 mrルーチンの一般的な概要

mrルーチンの、一般的な使用法を以下に解説します。以下に記述する関数の多くは、失敗時に呼出しプログラムを終了 しないで、エラーコードを返すものと、呼出しプログラムを終了させるものの、相対する2種類の関数を提供します。 また、検索や条件定義のためにも、多くの関数を提供します。次の章では、関数の使用方法に関する解説と、サンプル プログラムを提供します。

データベースディレクトリ、テーブル名、オープンするモードを指定し、mropen関数を実行すると、テーブルをオープンし 、データディクショナリーに設定されたレベルにより、ロックを行いテーブル記述子のポインタを返します。 一旦テーブルがオープンされると、mrmkrec関数により、テーブル記述子からレコード記述子のポインタを取得します。 その後、数々の操作を行なった後に、mrclose関数によってテーブルをクローズします。

フィールドの操作を行なう場合には、フィールド識別子を取得するために、mrigeta関数、またはmrngeta関数を使用します。 既に記述子がある場合には、mrganame関数を使用して、フィールド名を取得できます。

レコードを検索する場合には、mrgetbegin関数により初期化します。この関数は、検索条件をテーブルのレコードと関連付け します。検索条件がない場合でも、mrgetbegin関数は呼出しが必要となり、ソートされた検索を行なう場合には、代わりに mrsrtbegin関数を使用します。

検索条件は、mrqcon関数、mrqrng関数、mrqatr関数、mrqmch関数、mrqnul関数を使用して設定します。これらの関数は、 フィールド値を定数、範囲、他のフィールド値と比較し定数とのマッチングや、NULLとの比較を行なうために使用されます。 この時使用される値が、外部フォーマットの場合には、mrcvt関数により、ファイルフォーマットへ変換しなくてはなりません。 複雑な検索条件には、ANDやORまたはNOTを指定しなくてはなりません。その場合には、mqrand関数、mrqor関数、 mrqnot関数を使用します。

検索は、mrget関数とmrprev関数を繰り返し使用することによって実行されます。mrget関数（またはmrprev関数）を使用する ごとに、定義されたレコード構造に、内部フォーマットでレコード値が保存されます。他のプロセスによりロックされ、一時的に アクセスできない場合には、再検索するためにmrreget関数（またはmrreprev関数）を使用します。mrspv関数は、フィールド値 の、保存用スペースを割当てるために使用します。mrcopyv関数は、そのスペースに値を保存します。（TEXTデータタイプの 場合には、mrcopyv関数の代わりに、mrgetvs関数を使用しなくてはなりません。）こうして、アプリケーションプログラムによって 、検索と操作が可能な文字列による、外部フォーマットが作成されます。

mrfree関数は、mrspv関数によって、割当てられたスペースを開放します。

フィールドの集計関数（COUNT、MIN、MAX、AVG、SUM）は、mrgfunc関数によって実行されます。

新しいレコードを作成するには、mrputvs関数（フィールド値をNULLにする場合は、mrsetnv関数）を使用して、フィールド値 をレコード構造に付加します。外部フォーマットではなく、内部フォーマットでプログラムする場合には、mrputvs関数の 代わりに、mrputi関数を使用します。mrsetnr関数を使用して、レコード全体を明示的に、NULLに設定できます。 そしてmradd関数を使用して、レコードがテーブルに追加されます。mraddend関数は、追加処理のクリーンアップを行い ます。レコードの追加が行なえない可能性がある場合（ユニークインデックスが設定されているのに、重複値が入力されたり、 レコードレベルのロックがかかっているなど）、処理の結果を通知する、mrtadd関数を使用してください。

レコードを削除するには、mrdel関数またはmrtdel関数を使用します。また削除後には、mrdelend関数を使用して、クリーン アップを行ないます。

更新は、新しいレコードを作成するために、mrmkrec関数を使用し、レコードをコピーして使用するので、mrcopyr関数を 使用します。また、フィールド値を変更するためにmrputvs関数を使用し、更新後のレコードに置き換えるために、mrput関数 を使用します。

レコード構造に割当てたスペースは、mrfrrec関数を使用して解放します。必要なくなったスペースは、必ず開放するように プログラムしてください。

データベースのデータディクショナリーは、mropdict関数によりオープンされ、mrcldict関数によってクローズします。

トランザクションは、mrtrstart関数によって開始し、mrtrcommit関数またはmrtrcancel関数によって、コミットやキャンセルを 行います。また、トランザクション中のセーブポイントは、mrtrsave関数によって設定し、セーブポイントまでのロールバックは mrtrrollback関数を使用します。

表現式を構築する場合には、mrebegin関数を使用して開始し、mreend関数を使用して終了します。式はmrerun関数に よって評価され、mrqexpr関数を使用して制限に変換されます。評価後にmrefree関数を使用して解放します。 エラーが検知された場合には、mreabort関数を使用して、構築を中止します。表現式の構築では、mrecons関数、 mreivar関数、mrerecattr関数が、それぞれ定数、変数、フィールドを次の引数として、付加するのに使用されます。 関数を付加するには、mrefunc関数が使用されます。mrenull関数は、最終の引数がNULLであるかチェックし、 mrgdtpar関数は、データタイプ記述子をチェックし、mrecvarg関数は、表現式タイプを指定のデータタイプに変換します。

## 2.10 データベース、テーブル、フィールド名

mrルーチンの多くの引数は、データベース名、テーブル名、フィールド名を指定するか、データ値を指定します。一般的に 、これらの引数は文字列です。

複数のデータベースに、同一のテーブル名が存在する場合、以下に示すようにデータベース名とコロンが、テーブル名の 前に指定されます。

       database:table

同様にフィールド名は、テーブル名とピリオドを指定することで特定されます。さらにデータベース名を指定しても特定する ことができます。

       attribute
       table.attribute
       database:table.attribute

テーブルのフィールド名を間違えたために発生するエラーは、デバッグは難しいので、テーブル名でフィールド名を特定 するようにしてください。

## 2.11 エラーメッセージ

mrルーチンを使用した場合の、5つのエラータイプを示します。

- プログラムバグ
- スペース障害
- ユーザエラー
- データベース障害
- ファイル障害

すべてのエラーは、以下のフォーマットで表示されます。

       *** エラータイプ *** エラーの詳細

プログラムバグ

プログラムバグのエラーメッセージは、アプリケーションプログラム内に、プログラミングミスがあることを表示します。 通常は、不正なパラメータを関数に受け渡すことにより発生します。例えば、readモードでオープンされた テーブルに、データを挿入しようとしたり、更新処理において、違うテーブルから、新旧のレコードを指定した 場合などに発生します。

スペース障害

このエラーは、プログラムがスペース不足で実行できない場合に表示されます。レコード記述子らフィールド記述子 などに、割当てたスペースは、必要がなくなった時点で解放するようにプログラムしてください。非常に多くの フィールドを持つテーブルを処理する場合にも、スペース障害が発生する場合があります。

ユーザエラー

このエラーは、アプリケーションの実行中に、入力されたデータによって発生する場合があります。例えば、 不正なテーブル名や、フィールド名を関数に受け渡した結果発生します。プログラムに書き込まれた、フィールド名 であれば、発見、修正は簡単ですが、実行中に入力されたものであれば、mrngeta関数などにより チェックする必要があります。

データベース障害

このエラーは、重大なエラーであり、データベースが破壊されている場合に発生します。

ファイル障害

mrルーチンが、アクセスできるはずのファイルにアクセスできない場合に発生します。一般的に重大なエラーで あり、データベースが破壊されている恐れがあります。

## 2.12 ロック

データベースのデータディクショナリーに、テーブルに対してロックが指定されている場合、テーブルまたはレコードは readモードまたはupdateモードでロックされます。データディクショナリーに適切なロックレベルが指定されていない場合 には、テーブルまたはロックを行なう関数を呼び出しても効果はありません。

テーブルまたはレコードを、readモードでロックする場合は、他のユーザもreadモードであればアクセスできます。従って 、このテーブルまたはレコードを更新したいユーザは、他のユーザが対象テーブルの処理を中止するまで、アクセスでき なくなります

テーブルまたはレコードを、updateモードでロックする場合は、他のユーザは誰も、読込みあるいは書込みのために、 そのテーブルまたはレコードをアクセスできなくなります。もし、一人のユーザが、テーブルまたはレコードを長時間に 渡ってロックしている場合、あるいはロックされたままで解除されない場合には、障害が発生する可能せいがあります。

テーブルは、read、update、deferredモードでオープンできます。テーブルをreadモードでオープンすると、テーブルに 対し、readロックを行ない、updateモードでオープンすると、updateロックを行います。また、deferredモードでオープン すると、普段はreadロックが行なわれ、更新処理の時だけupdateロックに変更されます。

テーブルレベルロックは、テーブルのオープン時に効力が発生し、グループレベルロックは、mrgetbegin関数の実行時 に効力が発生し、レコードレベルロックは、mrget関数実行時に効力が発生します。

msclrlkユーティリティ、empadmユーティリティは、ロックを解除することができます。またデバッグでは、MSDEBUG変数に abortを指定することにより、コアダンプを取得することができます。

## 2.13 移植性

mx/mrルーチンを呼び出す、実行モジュールは、以下の条件内で機種間での移動が可能です。

1. 互換性のあるオペレーティングシステム
2. Empressのバージョンが同一である

上記の条件を満たさない場合には、ターゲットマシンでの再コンパイルが必要になります。