問い合わせ言語コマンドは、mscallルーチンを使って C 言語プログラム中に組み込むことができます。 このルーチンは、引数としてデータベースディレクトリと 問い合わせ言語コマンドを指定するだけです。
mscall (database_directory, query_language_statement);
データベースディレクトリと問い合わせ言語コマンドの両方は文字列として 指定する必要があります。また、文字列は、アプリケーションプログラムによって 作成することができます。 このルーチンは、SQL ステートメント実行に成功した場合、"0"を返し、 失敗した場合は "0"以外の値を返します。 (失敗の原因として、問い合わせ言語コマンドの構文エラーまたは 無効なテーブルおよびアトリビュート名の指定が考えられます。)
ヘッダーファイル "mscc.h"は、mscallを使用するすべての C 言語アプリケーションでインクルードする必要があります。 このファイルには、mscallを含む、すべてのホスト言語インターフェイス ルーチンによって使用する定数およびデータタイプが定義されています。 ヘッダーファイルの内容を以下に示します。
/***********************************************************************
* (c) Copyright Empress Software Inc. 1983, 2003
***********************************************************************/
#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 */
mscc.hファイルはバージョンによって異なることに注意してください。 このファイルは、Empressディレクトリの下の以下の場所に置かれます。
mscallを使ってプログラムを作成するには2つの方法があります。
mscleanルーチンは、 プログラムを終了する直前にコールするプロシージャをスタック上に登録するために 使用することができます。
mscallを使用したプログラムは、"cc"ではなく、 "empcc"を使用してコンパイルする必要があります。 これはプログラムのコンパイル時に適切なEmpressライブラリに リンクすることを確実にします。 この点を除けば、"empcc"と"cc"は同じ働きをします。
以下の例のデータベース名は、repairsいう名前の論理データベースです。 データベースの物理位置は、システム上のどこに置いても構いません。
例 1
以下のプログラム"names.c"は、 personnelテーブルから名前を検索します。
#include <mscc.h>
#define DATABASE "repairs"
msmain ()
{
mscall (DATABASE, "select name from personnel");
}
例 2
プログラム"phone.c"は、 1人の従業員名を指定し、電話番号を検索します。
#include <mscc.h>
#define DATABASE "repairs"
#define BUFSIZE 512
msmain (argc, argv)
int argc;
char *argv[];
{
char *name, command[BUFSIZE];
name = argv[1];
sprintf (command,"
select phone from personnel dump where name =\
'%s'", name);
mscall (DATABASE, command);
}
例 3
プログラム"newphone.c"は、 指定した名前が1つだけであるかをチェックします。
#include <mscc.h>
#define DATABASE "repairs"
#define BUFSIZE 512
msmain (argc, argv)
int argc;
char *argv[];
{
char command[BUFSIZE], *name;
if (argc != 2)
{
fprintf (stderr, "Usage: phone \
employee_name\n");
msexit (1);
}
name = argv[1];
sprintf (command,
"select phone from personnel\
dump where name =\
'%s'", name);
mscall (DATABASE, command);
}
例 4
次の例は、phone プログラムの対話的なバージョン"getphone.c"です。
#include <mscc.h>
#define DATABASE "repairs"
#define NOTHING ""
#define BUFSIZE 512
msmain()
{
char name[BUFSIZE], command[BUFSIZE];
printf ("\nFIND phone number GIVEN employee's\name.\n");
printf ("To stop, enter \".q\"\n\n");
for ( ; ; )
{
do
{
printf ("Employee name: ");
gets (name);
if (strcmp (name, ".q") == 0 )
msexit (0);
} while (strcmp (name, NOTHING) == 0 );
printf ("\n");
sprintf (command,
"select phone from\personnel dump\
where name = '%s', name);
mscall (DATABASE, command);
printf ("\n");
}
}
例 5
プログラム"employees.c"は、 personnelテーブルのすべての従業員の名前と電話番号を検索し、 適切なヘッダーとともにカウント数を出力します。
#include <mscc.h>
#define DATABASE "repairs"
msmain()
{
printf ("Current Employees\n\n");
mscall (DATABASE, "select name, phone from\personnel");
printf ("Total Number of Employees = ");
fflush (stdout);
mscall (DATABASE, "select count from personnel\dump");
printf ("\n");
}
例 6
C プログラム "loans.c"は、 指定された各従業員のローン残高の詳細を出力します。
#include <mscc.h>
#define DATABASE "repairs"
#define BUFSIZE 512
msmain (argc, argv)
int argc;
char *argv[];
{
char command[BUFSIZE], newcommand[BUFSIZE],*name;
int i;
if (argc < 2 )
{
print f("USAGE: %s employee's name\n", argv[0]);
exit (1);
}
for (i = 1 ; i < argc ; i++ )
{
name = argv[i];
printf ("Loans currently outstanding to\
%s:\n\n", name);
fflush (stdout);
sprintf (command,
"select date, amount from loans where \
name = '%s'", name);
mscall (DATABASE, command);
printf ("\n");
printf ("Total amount owing for %s: ", name);
fflush (stdout);
sprintf (command,
"select sum (amount) from loans dump \
where name = '%s'", name);
mscall (DATABASE, command);
printf ("\n\n");
}
name = argv[1];
sprintf (command,
"select sum (amount) from loans dump where \
name = '%s'" name);
for (i = 2 ; i < argc ; i++ )
{
name = argv[i];
sprintf (newcommand, " or name = '%s'", name);
strcat (command, newcommand);
}
printf ("\n\ntotal amount outstanding over ");
printf ("all of the above:");
fflush (stdout);
mscall (DATABASE, command);
}
このプロシージャは、これに対応するシェルプログラムと全く同じ処理結果を返します。
例 7
プログラム "menu.c"は、単純なメニュー操作を行うプログラムで、 標準 C インターフェイスによってEmpress 問い合わせ言語を実行し、 結果を表示します。 選択可能なコマンドは、以下になります。
#include <mscc.h>
#define DATABASE "repairs"
#define YES '1'
#define NO '0'
#define BUFSIZE 512
#define NAMESIZE 32 /* max length of ATTR names +1 */
#define NOTHING ""
#define NUMBER "n"
#define PHONE "p"
#define CREDIT "c"
#define RECORD "r"
#define LOANS "l"
#define QUIT "q"
char name[BUFSIZE];
char clause[BUFSIZE];
msmain ()
{
char showmenu;
char command[BUFSIZE],
attribute[NAMESIZE];
char table[NAMESIZE],
query[BUFSIZE];
printmenu ();
for ( ; ; ) /* loop through repeated queries */
{
strcpy (attribute, NOTHING);
strcpy (clause, NOTHING);
strcpy (table, "personnel");
showmenu = NO;
printf ("\nCommand: ");
gets (command);
if (strcmp (command, NUMBER) == 0)
{
strcpy (attribute, "number");
findname ();
}
else
if (strcmp (command, PHONE) == 0)
{
strcpy (attribute, "phone");
findname ();
}
else
if (strcmp (command, CREDIT) == 0)
{
strcpy (attribute, "credit_limit");
findname ();
}
else
if (strcmp (command, RECORD) == 0)
{
/* do nothing yet */
}
else
if (strcmp (command, LOANS) == 0)
{
strcpy (table, "loans");
}
else
if (strcmp (command, QUIT) == 0 )
{
msexit (0); /* normal termination */
}
else
{
showmenu = YES;
briefmenu ();
}
if (showmenu == NO) /* continue with query */
{
sprintf (query, "select %s from %s %s",
attribute, table, clause);
mscall (DATABASE, query);
}
}
}
printmenu ()
{
printf ("\n\n To select:\n\n");
printf ("An employee's personnel number %s\n", NUMBER);
printf ("An employee's phone number %s\n", PHONE);
printf ("An employee's credit limit %s\n", CREDIT);
printf ("All personnel records %s\n", RECORD);
printf ("All loans outstanding %s\n", LOANS);
printf ("To leave the program %s\n\n", QUIT);
}
briefmenu ()
{
printf ("\nPersonnel number (%s), phone (%s), ",
NUMBER, PHONE);
printf ("credit limit (%s), all records (%s), \n", CREDIT,
RECORD);
printf ("all loans (%s), or quit (%s)\n",
LOANS, QUIT);
}
findname ()
{
do
{
printf ("Enter employee name: ");
gets (name);
} while (STRCMP (name, NOTHING) == 0);
sprintf (clause, "where name = '%s'", name);
}
問い合わせ言語よりも複雑な方法でアトリビュート値を扱う場合、 問い合わせ言語によって作成されたダンプファイルのアトリビュート値の ポインタを取得するために msgvinitおよびmsgvalルーチンを使用します。 msgvlineルーチンは、カレントレコード番号を返し、 msgplineルーチンは、ダンプファイルのカレント行数を返します。
msgvinitルーチンは、 fopenによって返されたEmpressダンプファイルへのポインタを その引数として使用し、このファイルから値を取得するための初期化を行います。 常にこのルーチンは値の取得の前にコールしなくてはなりません。
msgvalルーチンは引数を必要とせず、文字列のアトリビュート値を返します。 ファイルの終了では(char *)0を返し、行の終了 (LIST DUMPコマンドによってダンプファイルを作成した場合は 通常、レコードの終了になります。) では、(char *)-1を返します。
msgvalを連続的にコールすると、それごとにアトリビュート値が返され、 すべての値が検索されるまで、アトリビュートごと、またレコードごとに ダンプファイルを通じて処理されます。 例えば、loansテーブルから全レコードを検索し、利息を加えた総額を出力する場合、 1 レコードのすべての値を検出した時に行の終了をチェックし、 必要なアトリビュートごとにmsgvalをコールし、 msgvalが、(char *)0を戻すまで実行するためのループが必要になります。
msgvlineは、引数を必要とせず、 LONGINTEGER型としてダンプファイル のカレント行数を返します。 通常、DUMPコマンドによってファイルを作成した場合、 レコード数のカウントになり、 DUMP LISTコマンドによってファイルを作成した場合、 アトリビュート数のカウントを返します。
msgplineは、引数を必要とせず、使用された場合、 DUMPおよびLIST DUMPコマンドに関わらず LONGINTEGER型としてダンプファイル のカレントレコード番号を返します。
例 1
プログラム"statement.c"は、 ローンの利息計算を行い、指定された従業員の月別データの単純な出力をします。 dollar型アトリビュート値をfloat型で返すための有益なdollcvtルーチンを この例では含んでいます。
#include <mscc.h>
#define DATABASE "repairs"
#define TEMP "msdump"
#define RATE 0.02
#define BUFSIZE 128
extern double dollcvt ();
msmain (argc, argv)
int argc;
char *argv[];
{
FILE *file;
int loan_no, counter;
char *name, *value;
char command[BUFSIZE];
double amount, interest, total, sum, limit;
for (counter = 1; counter < argc; counter++)
{
name = argv[counter];
sprintf (command, "select credit_limit from \
personnel dump into '%s' where \
name = '%s'", TEMP, name);
mscall (DATABASE, command);
file = fopen (TEMP, "r");
msgvinit (file);
value = msgval ();
fclose (file);
if (value == (char *)0)
{
printf ("\n\n***** Cannot find any");
printf ("record of employee '%s' in the database *****\n",
name);
}
else
{
limit = dollcvt (value);
sprintf (command, "select date, amount from loans dump\
into '%s' where name = '%s'",
TEMP, name);
mscall (DATABASE, command);
printf ("\n\n\n");
printf ("Monthly Statement for %s\n", name);
printf ("*********************************\n\n");
printf ("Date Amount Interest Total\n\n");
file = fopen (TEMP, "r");msgvinit (file);
value = msgval ();/* get first date */
if (value == (char *)0)
{
printf ("No loans outstanding\n\n");
printf ("Credit limit = $%-.2f\n",limit);
continue;
}
loan_no = sum = 0;
for ( ; value != (char *)0 ; )
{
printf ("%-7s", value); /* print date */
value = msgval (); /* get amount */
printf (" $%-9s", value); /* print amount */
amount = dollcvt (value);
interest = amount * RATE;
total = amount + interest;
printf ("$%-8.2f $%-8.2f\n", interest, total);
sum = sum + total;
value = msgval (); /* check end-of-line */
if (value == (char *)-1)
{
loan_no++;
value = msgval (); /* get next date */
}
}
fclose (file);
printf ("\nNumber of loans = %d \n", loan_no);
printf ("Credit limit = $%-2.f\n", limit);
printf ("Total Debts = $%-.2f\n", sum);
if (sum >= limit)
{
printf ("***** Please note: \ your credit limit is");
printf ("exceeded *****\n");
}
}
}
unlink (TEMP);
}
double dollcvt (string)
char *string;
{
extern double atof ();
char c, buffer [BUFSIZE], *buf_ptr;
for (buf_ptr = buffer ;
(c = *string++) != '\0' ;
)
if (c != '$' &&
c != '*' &&
c != ' ' &&
c != ',')
*buf_ptr++ = c;
*buf_ptr = '\0';
return (atof (buffer));
}