PostgreSQLをプログラムで操作する:PostgreSQLで作るLinuxデータベース(3)
前回までにPostgreSQLの歴史やインストール方法について説明してきた。今回は、実際にPostgreSQLとPerlやC言語を使ったアプリケーションを開発する方法について解説する。
今回のおもな内容
- サンプルデータベースの作成
- PerlによるPostgreSQLの操作
- C言語によるPostgreSQLの操作
- PHP3によるPostgreSQLの操作
- PostgreSQLの開発環境
PostgreSQLはいろいろな言語とのインターフェイスを持っていますが、今回は代表的なところとして、PerlとC言語でのインターフェイスや、PostgreSQLと一番組み合わせて使われることが多いと思われるApacheおよびPHP3を使ってのアプリケーション開発についても説明したいと思います。
1.サンプルデータベースの作成
何をするにしても、データベースがなければ話になりません。そこで、今回紹介するプログラムで使うためのサンプルデータベースを作成しましょう。とりあえず、氏名と電話番号および電子メールアドレスを管理する簡易アドレス帳ということにします。
まず、PostgreSQLのプロンプトでcreate table文を発行して、テーブルを定義します。
postgres=> create table addrbook (name varchar(50),telno varchar(50), email varchar(50));
テーブルが作成できたらテストデータを入力するのですが、一から作成するのは大変なので、先に用意しておいたデータからコピーすることにします。
以下の内容のテキストファイルを用意し、addrbook.txtというファイル名で保存します。スペースの部分はTABにしてください。
R.Munechika 070-6682-**** munetika@myhome.niji-net.com H.Nishida 090-****-**** nishida@hoge.co.jp T.Miyahara 090-9999-9999 tmiyahar@red.gr.jp
このファイルをcopyコマンドを使ってインポートします。
postgres=> \copy addrbook from addrbook.txt Successfully copied.
コピーされた内容を確認します。
postgres=> select * from addrbook; name |telno |email -----------+-------------+---------------------------- R.Munechika|070-6682-****|munetika@myhome.niji-net.com H.Nishida |090-****-****|nishida@hoge.co.jp T.Miyahara |090-9999-9999|tmiyahar@red.gr.jp (3 rows)
以上でサンプルデータベースの用意ができました。
2.PerlによるPostgreSQLの操作
Perlインターフェイスの導入
PostgreSQLにPerlからアクセスするには、インターフェイスを導入しなければなりません。
PostgreSQLのソースを展開したディレクトリにあるsrc/interfaces/perl5ディレクトリに移動します(ここでは、/usr/local/src/postgresql-6.5.3とします)。
$ cd /usr/local/src/postgresql-6.5.3/src/interfaces/perl5
ここで、Makefile.PLをPerlから実行します。
$ perl Makefile.PL
コンパイルを実行します。
$ make
rootになってインストールを行います。
$ su # make install
Perlのプログラム(表示用)
PerlでPostgreSQLに作成したデータベーステーブルの表示を行うプログラムを作成してみます。以下は、先ほど作成したテーブルの内容を表示する簡単なプログラムのリストです。
#!/usr/bin/perl use Pg; $dbname = "postgres"; $conn = Pg::connectdb("dbname=$dbname"); $res = $conn-> exec("select * from addrbook"); print "name telno email\n"; print "--------------------------------------\n"; while(@item = $res-> fetchrow) { print "@item[0] @item[1] @item[2]"; print ("\n"); }
1行目はPerlの実行ファイルの絶対パスを指定します。whichなどのコマンドで調べて、各自の環境に合わせてください。3行目がデータベース名の指定で、6行目がデータベースに対して実際にSQL文を発行する部分です。
8〜13行目までが表示を行う部分になります。まず10〜13行目でループを行い、1行ずつfetchを行ってレコードを取得し、printで出力します。
Perlのプログラム(追加用)
次にレコード追加を行うサンプルプログラムtest2.plについて説明します。
#!/usr/bin/perl use Pg; $dbname = "postgres"; $conn = Pg::connectdb("dbname=$dbname"); $res = $conn-> exec("insert into addrbook values('K,Hamano','070-8888-8888','hamano\@email.net')"); if ( $res -> resultStatus == PGRES_COMMAND_OK ) { print "OK\n" } else { print "NG\n" }
5行目まではtest1.plと同じですが、6行目のSQL文の発行部分が異なる点に注目してください。また、“@”を入力するような場合は、“\”を使ってエスケープすることに注意してください(実際のデータに“\”は登録されません)。
8〜13行目はエラー処理を記述しています。処理がうまく実行できなかった場合は、resultStatusに“PGRES_COMMAND_OK”以外のステータスを戻してきます。
test2.plを実行してから表示用のプログラムtest1.plを実行すると、レコードの追加が行われているのが分かります。
[postgres@micky postgres]$ ./test2.pl OK [postgres@micky postgres]$ ./test1.pl name telno email -------------------------------------- R.Munechika 070-6682-**** munetika@myhome.niji-net.com H.Nishida 090-****-**** nishida@hoge.co.jp T.Miyahara 090-9999-9999 tmiyahar@red.gr.jp K,Hamano 070-8888-8888 hamano@email.net
3.C言語によるPostgreSQLの操作
C言語のプログラム(表示用)
次に、C言語を使ってPostgreSQLのデータベーステーブルの中身を表示してみることとします。
/* ヘッダファイル取り込み */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "postgres.h" #include "libpq-fe.h" /* main処理 */ int main(int argc,char **argv) { /* 変数定義 */ char dbName[255] = "postgres"; /* データベース名はハードコーディング */ char sql[255]; int i; PGconn *con; PGresult *res; char *kou1,*kou2,*kou3; /* DBとの接続 */ con = PQsetdb("","",NULL,NULL,dbName); if ( PQstatus(con) == CONNECTION_BAD ) { /* 接続が失敗したときのエラー処理 */ fprintf(stderr,"Connection to database '%s' failed.\n",dbName); fprintf(stderr,"%s",PQerrorMessage(con)); exit(1); } /* select文の発行 */ sprintf(sql,"select * from addrbook"); res = PQexec(con,sql); if (PQresultStatus(res) != PGRES_TUPLES_OK) { /* SQLの実行に失敗したときのエラー処理 */ fprintf(stderr,"%s",PQerrorMessage(con)); exit(1); } printf("name telno email\n"); printf("--------------------------------------\n"); for(i = 0; i < 3 ;i++) { kou1 = PQgetvalue(res,i,0); kou2 = PQgetvalue(res,i,1); kou3 = PQgetvalue(res,i,2); printf("%s %s %s\n",kou1,kou2,kou3); } PQclear(res); }
C言語で記述する際は、postgres.hとlibpq-fe.hのインクルードをお忘れなく。また、PQexec()関数は以下のように第2引数にSQL文を代入して実行します。
/* select文の発行 */ sprintf(sql,"select * from addrbook"); res = PQexec(con,sql);
PQgetvalue()関数はデータベースから値を取り出すもので、第2引数に「行」、第3引数に「列」を指定します。そして、PQgetvalue()関数の戻り値をprintf()関数で整形して出力します。
kou1 = PQgetvalue(res,i,0); kou2 = PQgetvalue(res,i,1); kou3 = PQgetvalue(res,i,2); printf("%s %s %s\n",kou1,kou2,kou3);
コンパイル時は、PostgreSQLのヘッダファイルとライブラリファイルが存在するディレクトリに明示的にパスが通るようにします。
cc -o test1 test1.c -I$POSTGRES_HOME/include -L$POSTGRES_HOME/lib -lpq -lnsl -lcrypt
C言語のプログラム(追加用)
/* ヘッダファイル取り込み */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "postgres.h" #include "libpq-fe.h" /* main処理 */ int main(int argc,char **argv) { /* 変数定義 */ char dbName[255] = "postgres"; /* データベース名はハードコーディング */ char sql[255]; int i; PGconn *con; PGresult *res; /* DBとの接続 */ con = PQsetdb("","",NULL,NULL,dbName); if ( PQstatus(con) == CONNECTION_BAD ) { /* 接続が失敗したときのエラー処理 */ fprintf(stderr,"Connection to database '%s' failed.\n",dbName); fprintf(stderr,"%s",PQerrorMessage(con)); exit(1); } /* insert文の発行 */ sprintf(sql,"insert into addrbook values ('K,Hamano','070-8888-8888','hamano@email.net')"); res = PQexec(con,sql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { /* SQLの実行に失敗したときのエラー処理 */ fprintf(stderr,"%s",PQerrorMessage(con)); exit(1); } PQclear(res); }
表示するプログラムの変更個所はPerlのプログラムのときと同様、SQL文を発行するところとSQL文からの戻り値を判断するところです。C言語でもPerlと同じような処理を行えばよいということが理解できるでしょう。
4.PHP3によるPostgreSQLの操作
PHP3からPostgreSQLにアクセスするには、PHP3を導入します。ここではDSO版のApacheを使うものとして説明します。以後の操作はrootで作業します。
Apacheのインストール
# cd /usr/local/src # tar xfz apache_1.3.12.tar.gz # cd apache_1.3.12 # ./configure --enable-module=so # make # make install
PHPのインストール
# cd /usr/local/src # tar xfz php-3.0.15-i18n-ja.tar.gz # cd php-3.0.15-i18n-ja # ./configure --with-pgsql --with-apache=../apache_1.3.12 --enable-track-vars --with-apxs=/usr/local/apache/bin/apxs --enable-i18n --enable-mbregex # make # make install
httpd.confの編集
Apacheの標準の設定ではPHP3が実行できないようになっていますので、設定ファイル(httpd.conf)を編集します。
#AddType application/x-httpd-php3 .php3 #AddType application/x-httpd-php3-source .phps
という個所のコメント行の「#」を削除して、設定を有効化します。httpd.confを編集したら、必ずApacheを再起動してください。
PHP3のプログラム(表示用)
PHP3のプログラムとPerlやC言語でのプログラムとの相違点は、PHP3はサーバサイドで実行し、クライアント(Webブラウザ)で表示するというところにあります。
<HTML> <HEAD> <META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=EUC-JP"> <title> 簡易アドレス帳 </title> </HEAD> <BODY BGCOLOR="#FFFFFF"> <h1>簡易アドレス帳</h1> <br> <hr> <br> <? /* Global variables. */ $dbname = "postgres"; /* DB name of PostgreSQL. */ $tbname = "addrbook"; /* table name of PostgreSQL. */ /* データベースとの接続 */ $conn = pg_Connect("localhost", "5432", "", "", $dbname); if (!$conn){ echo "データベースの接続でエラーが発生しました<BR>\n"; exit; } /* SQL文の発行 */ $sql = "select * from $tbname"; $result = pg_Exec($conn, $sql); if (!$result) { echo "検索でエラーが発生しました<BR>\n"; exit; } $num = pg_numrows($result); echo "<TABLE BORDER=\"1\">\n"; echo "<TR><TD>名前</TD><TD>電話番号</TD><TD>メール</TD></TR>\n"; for ($i = 0; $i < $num; $i++) { $row = pg_fetch_row($result, $i); echo "<TR><TD>" . $row[0] . "</TD><TD>" . $row[1] . "</TD><TD>" . $row[2] . "</TD></TR>\n"; } echo "</TABLE>\n"; ?> </BODY> </HTML>
PHP3の文法はC言語によく似ているので、HTMLタグを除けば先ほどのC言語のサンプルプログラムとほとんど変わらないことにお気付きになるでしょう。
PHP3のプログラム(追加用)
次にPHP3でのレコード追加プログラムの例を示します。HTMLフォームでデータを入力し、そのHTMLフォームからPHP3プログラムを実行することにより登録を行います。リスト6はPHP3プログラムを呼び出すHTML、リスト7がPHP3プログラムです。
<html> <head> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=EUC-JP"> <title> 簡易アドレス帳(追加) </title> </head> <body bgcolor="FFFFFF"> <TABLE align="center" BORDER="0"> <TR><TD WIDTH="600"> <table align="center" border="5"> <TR> <TD align="center"> <FONT SIZE="5"><B>簡易アドレス帳(追加)<BR> </B></FONT> </TD> </table> <br> 登録してください <BR><BR> </TD></TR> </TABLE> <BR> <P align="right"> <hr> <form method="post" action="./test2.php3" NAME="myForm"> <TABLE ALIGN="CENTER" BORDER="1" WIDTH="600"> <input type="hidden" name="ename"> ※(*)がついている項目は、必ず入力してください。<BR> <TR> <TD WIDTH="100" BGCOLOR="#CCCCFF">名前 (*)</TD><TD><input type="text" name="name" size="60" maxlength="80"></TD> </TR> <TR> <TD WIDTH="100" BGCOLOR="#CCCCFF">電話番号 (*)</TD><TD><input type="text" name="telno" size="60" maxlength="80"></TD> </TR> <TR> <TD WIDTH="100" BGCOLOR="#CCCCFF">メール (*)</TD><TD><input type="text" name="email" size="60" maxlength="120"></TD> </TR> </TABLE> <center> <input type="submit" value="登録"><input type="reset" value="リセット"> </CENTER> </form> </body> </html>
<HTML> <HEAD> <META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=EUC-JP"> <title> 簡易アドレス帳(追加) </title> </HEAD> <BODY BGCOLOR="#FFFFFF"> <FORM ACTION="test2.php3" METHOD=POST> <H2> 簡易アドレス帳(追加)<BR> </H2> <? /* Global variables. */ $dbname = "postgres"; /* DB name of PostgreSQL. */ $tbname = "addrbook"; /* table name of PostgreSQL. */ /* データベースとの接続 */ $conn = pg_Connect("localhost", "5432", "", "", $dbname); if (!$conn){ echo "データベースの接続でエラーが発生しました\n"; exit; } $sql = "insert into $tbname values ('$name','$telno','$email')"; $result = pg_Exec($conn, $sql); if (!$result) { echo "データベースへの登録でエラーが発生しました<BR>\n"; exit; } echo "登録しました<BR>\n"; ?> </BODY> </HTML>
これもC言語の例と同じく、あまり変わりがないことがお分かりになるでしょう。
5.PostgreSQLの開発環境
第1回の原稿に書いたとおり、PostgreSQLにはレプリケーションが実装されていないために、つい最近まではPostgreSQLを使用してシステムインテグレーションを行うのはいろいろと苦労がつきまとっていました。
ところが、レプリケーションを実装するための仕組みが最近になって現れてきました。1つが、筆者の所属する株式会社デジタルデザインが2000年11月より出荷を開始する「FCR for PostgreSQL」です。このソフトは2つのサーバ間にFast Connector Serverを置いて、insert文などの発行を受けてもう1つのサーバにトリガを使ってレプリケーションを行う仕組みになっています。評価版がダウンロードできますので、一度お試しになられてはいかがでしょう。
また、導入方法などについては下記のURLが参考になります。
もう1つの実装は、株式会社グッデイの細川さんがGPL2で公開されている「Usogres」です。
UsogresはPostgreSQLのプロキシとして機能するサーバソフトです。Usogresで実行されたSQLの処理が複数のPostgreSQLサーバーに送られるので、結果的にリアルタイムでバックアップされるというものです。しかし、厳密的な意味でのレプリケーションはまだ実現されていません。作者の細川氏によると、今後本格的なレプリケーション機能を実装するとのことなので大いに期待が持てるソフトです。
今回まで3回にわたりPostgreSQLの説明を行ってきました。PostgreSQLの概要や導入方法、アプリケーション開発について、おおよそ理解できたと思います。この連載が皆さんのお仕事に生かされることを願ってやみません。
Copyright © ITmedia, Inc. All Rights Reserved.