COBOL+Apache+PostgreSQL

2002/03/15


アクセスカウンターをCOBOLで作成してみました。カウンターのデータはPostgreSQLで管理するようにしました。
フリーCOBOLとApacheとPostgreSQL。この組み合わせ結構面白いように思います。

COBOL TinyCOBOLを使用(将来的にはOpenCOBOLで作成予定)。
PostgreSQLのアクセス部分はTinyCOBOLのtest.code/tbd02/tdb02a.cを使用。
コンパイルはTinyCOBOLのtest.code/tbd02/MakefileのCOBOLのプログラム名を今回作成したCOBOLのプログラム名(cgi02.cob)に変える事のみでmake。
Apacheの設定 特に何も無し。(インストールした時の初期設定)
ユーザーは/etc/httpd/conf/httpd.confの初期値のnobody(User nobody)を使用。
PostgreSQLの設定 createuserでnobodyをPostgreSQLのユーザに追加。
ユーザnobodyに対してGRANTでアクセス権を与える。
libpq.so.2にリンクを設定する。
  cd /usr/lib
  ln -s /usr/local/pgsql/lib/libpq.so.2 .
  ln -s /usr/local/pgsql/lib/libpq.so.2.0 .

以下の内容でデータベースを作成
データベース名 web
テーブル名 count
列名 key(TEXT) count(INTEGER)
keyは”1”固定です。countはアクセスされるたびに1が加算されます。


上記の設定でCOBOLのアクセスカウンターが実行されます。
こちらをクリックでこのアクセスカウンターが起動されます。
(但し、このサーバーは自宅サーバーです。一日数時間しか立ち上がっておりません。)
 
以下ソースを紹介します。

今回作成したCOBOLソースです。
 IDENTIFICATION  DIVISION.
 PROGRAM-ID.    cgi02.
 ENVIRONMENT     DIVISION.
 CONFIGURATION   SECTION.
 INPUT-OUTPUT    SECTION.
 DATA DIVISION.
 FILE SECTION.

WORKING-STORAGE SECTION.
 01 wk-count pic x(05).
 77 DATABASE-NAME                  PIC X(80).
 77 SQL-QUERY                      PIC X(200).
 77 DB-HANDLE                      PIC 9(12) COMP.
 77 QRY-HANDLE                     PIC 9(12) COMP.
 77 NTUPLE                         PIC 9(12) COMP.
 77 NFIELD                         PIC 9(12) COMP.
 77 MAX-TUPLE                      PIC 9(12) COMP.
 77 MAX-FIELD                      PIC 9(12) COMP.
 77 COLUMN-VALUE                   PIC X(80) VALUE SPACES.
 77 CMD                            PIC 9.
 77 DB-STATUS                      PIC 9(12) COMP.
 77 DB-MESSAGE                     Pic X(200).
 01 MYTBL-RECORD                   PIC X(15).
*
 PROCEDURE DIVISION.
 A-000.
*
*---- DB CONNECT ----*
   MOVE    "web"                TO  DATABASE-NAME.
   CALL    "sql_connect_db"     USING  DATABASE-NAME
                                       DB-HANDLE
                                       DB-STATUS.
   IF  DB-STATUS               NOT =   ZEROS
       DISPLAY "Error in database connection!"
       STOP RUN.
*
*---- DB SELECT  ----*
   STRING "UPDATE count SET count = count + 1 where key = '1';;" INTO SQL-QUERY.
   CALL "sql_exec_query"        USING  DB-HANDLE
                                       SQL-QUERY
                                       QRY-HANDLE
                                       DB-STATUS.
   IF (DB-STATUS               NOT =   1  AND
       DB-STATUS               NOT =   2)
       MOVE    SPACES              TO  DB-MESSAGE
       CALL "sql_status_message" USING DB-HANDLE
                                       DB-MESSAGE
       DISPLAY DB-MESSAGE.
*
*---- DB SELECT  ----*
   STRING "select count from count where key = '1';;" INTO SQL-QUERY.
*
   CALL "sql_exec_query"        USING  DB-HANDLE
                                       SQL-QUERY
                                       QRY-HANDLE
                                       DB-STATUS.
   IF (DB-STATUS               NOT =   1  AND
       DB-STATUS               NOT =   2)
       MOVE    SPACES              TO  DB-MESSAGE
       CALL "sql_status_message" USING DB-HANDLE
                                       DB-MESSAGE
       DISPLAY DB-MESSAGE.
*
   CALL "sql_max_tuple"         USING  QRY-HANDLE
                                       MAX-TUPLE.
   CALL "sql_max_field"         USING  QRY-HANDLE
                                       MAX-FIELD.
   MOVE    ZERO                    TO  NTUPLE
   PERFORM UNTIL NTUPLE = MAX-TUPLE
        CALL "sql_get_tuple"    USING  QRY-HANDLE
                                       NTUPLE
                                       MYTBL-RECORD
        ADD    1                   TO  NTUPLE
   END-PERFORM.
*
   CALL "sql_clear_query"       USING  QRY-HANDLE.
*
*---- DB DISCONNECT ----*
   CALL "sql_disconnect_db"     USING  DB-HANDLE.
*
   MOVE    MYTBL-RECORD            TO  wk-count.
  display wk-count.
 A-999.     
   EXIT-PROGRAM.

PostgreSQLのアクセス部分(TinyCOBOLのtest.code/tbd02/tdb02a.c)のソースです。
/* test program for libpq (postgresql) */

#include <stdio.h>
#include <stdlib.h>

#include <libpq-fe.h>

void
do_exit(PGconn *conn) {
	PQfinish(conn);
	exit(1);
};

/* this function assumes a command buffer of 80 characters */
void 
sql_exec_query( int *dbhandle, char *query, int *qryhandle, int *status ) {
	char *r,*s=query;
	int nfields, i, j;
	PGconn *conn = (PGconn *)*dbhandle;
	PGresult *res;

	/* detect end of query with 2 successive ';' */
	while ( *s != ';' || *(s+1) != ';' ) s++;
	*s=0;
	res = PQexec(conn, query);
	*status = PQresultStatus(res);
	*qryhandle = (int) res;
}

void
sql_status_message( int *dbhandle, char *message ) {
	PGconn *conn = (PGconn *)*dbhandle;
	char *s;
	s = PQerrorMessage(conn);
	while (*s) {
		*message++ = *s++;
	}
}

void
sql_max_tuple( int *qryhandle, int *maxtuple ) {
	*maxtuple = PQntuples((PGresult *)*qryhandle);
}

void
sql_max_field( int *qryhandle, int *maxfield ) {
	*maxfield = PQnfields((PGresult *)*qryhandle);
}

void
sql_get_value( int *qryhandle, int *ntuple, int *nfield, char *value ) {
	char *s;
	s = PQgetvalue((PGresult *)*qryhandle,*ntuple,*nfield);
	while (*s) {
		if (*s == '\n') continue;
		*value++ = *s++;
	}
}

void
sql_get_tuple( int *qryhandle, int *ntuple, char *tuple ) {
	char *s;
	int nfield=0;
	int maxfield = PQnfields((PGresult *)*qryhandle);
	while (nfield < maxfield) {
		s = PQgetvalue((PGresult *)*qryhandle,*ntuple,nfield);
		while (*s) {
			*tuple++ = *s++;
		}
		nfield++;
	}
}

void
sql_clear_query( int *qryhandle ) {
	PQclear((PGresult *)*qryhandle);
}

void
sql_connect_db( char *dbname, int *dbhandle, int *status ) {
	PGconn *conn;
	char db[81];
	char *s;
	/* trim right spaces on the buffer */
	memmove(db,dbname,80);
	db[80]=0;
	s = db+79;
	while ((s >= db) && (*s == ' ')) s--;
	if (s >= db) 
		*(s+1)=0;
	conn = PQsetdb("","","","",db);
	*status = PQstatus(conn);
	*dbhandle = (int)conn;
}

void
sql_disconnect_db( int *dbhandle ) {
	PGconn *conn = (PGconn *)*dbhandle;
	PQfinish(conn);
}


呼び出し元のHTMLのソースです。
<HTML><HEAD>
<TITLE>COBOL カウンター</TITLE></HEAD>
<BODY><H1>カウンター</H1>あなたで<!--#exec cmd="../cgi-bin/cgi02"-->人目です。<br>
</BODY></HTML>

実行環境 Vinelinux2.1 Tinycobol0.57 apache1.3.14 PostgreSQL7.1
参考書籍 改訂第3版 PC UNIXユーザのためのPostgreSQL完全攻略ガイド