次に、上記のような問い合わせを、ユーザ・インターフェイスに Web を使っ て行なうことを考えましょう。Web ブラウザの画面からデータベースを検索で きれば、呪文のような SQL を入力しなくて済むので使い勝手が向上します。 今回はごく単純に、「都市名」と、その都市に対して「東西南北」のどれかを 指定することによって、データベースを検索して条件にあった都市名を表示す るようにしましょう。このような画面は、「フォーム」を使うと簡単に実現で きます(図 3 、リスト 1)。
1 <html>
2 <head><title>small city database</title></head>
3 <body>
4 都市データベースを検索するパラメータを入力して下さい。
5
6 <form method="GET" action="select.cgi">
7 都市名<input type="text" name="city">の
8
9 <select name="opt">
10 <option>北
11 <option>南
12 <option>東
13 <option>西
14 </select>
15 にある都市は?
16 <p>
17 <input type=submit value="検索開始">
18 </form>
19 </body>
20 </html>
リスト1test.html
フォームを使うと、ブラウザ上にユーザ入力のエリアが表示されます。フォー ムには、入力エリアとしていくつか種類がありますが、今回は都市名の入力エ リアとして、自由にテキストを入力できる ``text'' (7 行目)と、東西南北の指 定のために ``select'' (9 行目) を使います。
その他、入力データを Web サーバに送信するためのボタンが必要ですが、こ れは 17 行目の input type=submit... で指定しています。
6 行目の form method... はフォームの開始を指示しますが、それ以外 に、起動されるべき CGI プログラムを指示すると言う重要な役割があります。 action=``select.cgi'' がそれですが、この場合、リスト1の html ファイル と select.cgi が Web サーバ上で同じディレクトリにあることが前提になっ ています。もしも select.cgi を特定のディレクトリに置く必要がある場合は、 パス名を追加して下さい。たとえば、action=``/cgi-bin/select.cgi''などと なるでしょう。このほか、お使いのサーバの設定によって考慮すべき点がある かも知れません。うまくいかない場合は、サーバの管理者に相談してみて下さ い。
そのほかに気をつけることとしては、
createuser nobody
となります。
リスト 1 のフォームで、「検索開始」ボタンを押すと、リスト 2 の shell script select.cgi が起動されます。このプログラムの処理概要は以下のよう になります。
では、リスト2 を見ながら具体的な処理の流れを追っていきましょう。
1 #!/bin/sh
2 cgiparse=/usr/local/etc/cgiparse
3 psql=/usr/local/postgres95/bin/psql
4 dbhost=foo
5
6 echo Content-type: text/plain
7 echo
8
9 city=`$cgiparse -value city`
10 opt=`$cgiparse -value opt`
11
12 case $opt in
13 北)
14 op='!^';;
15 南)
16 op='!|';;
17 西)
18 op='!<';;
19 東)
20 op='!>';;
21 esac
22
23 query="select c1.name from city c1, city c2 where c2.name = '$city' and c1.loc $op c2.loc;"
24
25 echo "$city より $opt にあるのは:"
26 $psql -h $dbhost -t -c "$query" test
リスト2 select.cgi
6 行目では、 ``Content-type: text/plain'' という HTTP ヘッダを生成してい ます。通常 HTTP ヘッダは Web サーバが自動的に作ってくれるので意識する 必要がないのですが、CGI では少なくとも Content-type: というフィールド を自前で用意する必要があります。これを忘れると、何もブラウザに表示され ないので注意して下さい。なお、Content-type: フィールドは Web サーバに 対して CGI が生成するドキュメントの種類を教えるためのもので、この例で は、text/plain (いわゆる「プレーン・テキスト)となっています。
HTTP ヘッダの終了を示すために 7 行目で空行を出力した後、9, 10 行目でフォー ムから渡されたパラメータの解析を cgiparse を使って行ないます。cgiparse は、CERN httpd という Web サーバに付いてくるツールで、CERN httpd 以外 の環境でも使うことができます。
ここで、フォームに入力されたパラメータについてお話します。この例では、 select.cgi が起動されるときに 環境変数 QUERY_STRING に以下のような形式 でパラメータがセットされます。
name1=param1&name2=param2...
name1, や name2 はフォームの name=... で指定された文字列です。御覧のよ うに、name の後に = が来て、その後に入力された値がセットされます。 select .. の場合には、option で指定された値のうち、ユーザが選択し た値が入ります。複数の入力項目の区切りは ``&'' です。たとえば、リスト 1 で、都市名に ``東京'' 、東西南北の選択が ``北'' であった場合、
city=東京&opt=北となるはずですが、実際には
city=%C5%EC%B5%FE&opt=%CB%CCが QUERY_STRING にセットされます。%C5 などの暗号のような文字列は 「URL エンコーディング」と呼ばれる規則にしたがって変換された結果です(実はさ きほどの ``='' や ``&'' の使い方も URL エンコーディングの一部なのですが)。 この規則によれば「値」の文字列は以下の規則にしたがって変換されます。
こういったややこしいことは cgiparse を使えば簡単に処理できます。 cgiparse は -value で指定された文字列を name とみなし、URL エンコーディ ングをもとに戻し、標準出力に吐き出します。select.cgi では cgiparse を 使って 9 行目、10 行目のように shell 変数 city, opt に値をセットしてい ます。
cgiparse と同じ機能を持つプログラムは、ほかにもたくさんあります。たと えば、perl で書かれた cgi-lib.pl (http://www.bio.cam.ac.uk/cgi-lib/) は perl で CGI を使う場合に大変便利です。
フォームから渡された検索パラメータが解析できれば、後は select 文を作る だけです。12 行目から 21 行目までの case 文で「東西南北」を対応する PostgreSQL の operator に変換して shell 変数 op にセットし、23 行目で $city と $op を使って SQL を作っています
最後の行で psql のコマンドを発行します。ここで、psql のオプション -h は PostgreSQL の動いているホストを指定し、-c はインタラクティブではな く与えられた問い合わせをバッチ式に実行します。また、コマンドラインから 起動する場合と違って、カラム名とか ``(5 rows)'' のようなコメントを psql に出力してもらう必要はありませんから、-t でこれを抑止しています。