データベース(ODBC)との接続
httpd/Fasttrack/Enterprise/IIS/PWS
PerlモジュールWin32::ODBCを使うとODBC(Open DataBase Connectivity)をサポートするデータベースと接続することができます。ここではAccess97と接続することを例にとります。

Access97をすでにインストールしてあり、Access97インストール時等に32ビットODBCドライバもすでにインストールしてあることを前提にします。ODBCドライバはAccess97等に付属していますが、手元にない場合はMicrosoftのサイトから得られます。

http://www.microsoft.com/support/products/backoffice/odbc/
 

PerlモジュールWin32::ODBCを入手しインストールします。

ActiveState社 ActivePerl build 507 では標準でインストールされています。
もし、古いバージョンを使っていたりしてインストールされていない場合は次のサイトから入手します。

http://www.roth.net/ODBC/

インストール方法はパッケージに付属のReadme等を参照してください。
ActiveState Perl for Win32 の場合は ppm でインストールできます。

例として次の内容で設定を行います。
データベース名: Address.mdb
データソース名: 住所録
テーブル名: 住所テーブル
テーブル項目:
住所録ID 氏名 シメイ 配偶者名 住所1 都道府県 郵便番号 国名 電子メールアドレス 自宅TEL 会社直通TEL 会社内線番号 FAX番号 生年月日 年賀状の送付 備考

Access97でデータベースを作成します。ここでは、Access97でテンプレートデータベースから住所録を作成しています。
 

ODBCデータソース アドミニストレータでDSN(データソース名)を設定します。

スタート->設定->コントロールパネルを選び32ビットODBCをダブルクリックします。

システムDSNを選び、「追加」をクリックします。

データソースドライバとしてMicrosoft Access Driverを選び、「完了」をクリックします。

データソース名に適当な名前を入力します。ここでは、「住所録」とします。

次に既存のデータベースを選択します。選択ボタンをクリックしてAccessで作成したデータベースを選びます。選んだら「OK」ボタンをクリックします。

”ODBC Microsoft Access97 セットアップ”画面で「OK」をクリックするとシステムデータソースとして設定されます。

 

テストを行います。

コマンドモニタで test.pl でテストしてみます。test.pl はWin32::ODBCパッケージの中に含まれています。
 
perl test.pl test.pl

正常にインストールされている場合は、モニタ上にデータが表示され、エラーがないことが表示されます。


このサンプルスクリプトはテーブルのリレーションには対応していません。
検索画面等が表示されるまでは少し時間がかかるかもしれません。

[サンプルスクリプトの実行]
 
 
odbc.cgi
#!/usr/bin/perl
#
# odbc.cgi
#
# (C)1999 Kaoru Fujita
#
# データの[変更]はカラム属性のためか Access97 のテンプレート
# 住所録ではエラーとなるので無効としてある。
#
use lib './lib';
require 'jcode.pl';
require 'util.pl';

use Win32::ODBC;

#
# 定数
#
# タイトル
$Title = 'データベース接続サンプル プログラム';
# CGI の仮想パス
$CGIPath = '/cgi-bin';
# プログラム名
use File::Basename;
$Program = basename($0);
# 漢字コード
$CharSet = 'Shift_JIS';
$Encoding = 'sjis';


#
# メインプログラム
#
parseInput($Encoding);

initProc();

# テスト用
#$in{'Action'} = 'getData';
#$in{'DSN'} = 'test01';

$date = &getDate();
$act = $in{'Action'};

if ($act eq 'getData') {
        viewData();
}
elsif ($act eq 'getField') {
        viewField();
}
elsif ($act eq 'getQueryField') {
        viewQueryField();
}
elsif ($act eq 'modifyData') {
        modifyData();
}
elsif ($act eq 'addData') {
        addData();
}
elsif ($act eq 'deleteData') {
        deleteData();
}
else {
        viewData();
}

exit(0);


#
# <IN>  なし
# <OUT> 日時(String)
#
sub getDate
{
        ($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
        $year += 1900;

        return "$year/$mon/$mday $hour:$min:$sec";
}

#
# <IN>
# <OUT>
#
sub initProc
{
        print "Content-type: text/html\n\n";
}

#
# <IN>  なし
# <OUT> なし
#
sub viewData
{
        my(@table, $table);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # 列の最大値は?
    #$iTemp = $O->GetStmtOption($O->SQL_MAX_ROWS);

        # SQL の発行
        my($sql) = "SELECT * FROM [$table]";
        if ($O->Sql("$sql")) {
                exitError('Sql()が失敗しました: '.$O->Error()."\n".$sql);
                $O->Close();
        }
        @FieldNames = $O->FieldNames();

        my($cond);
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                my($fn) = $FieldNames[$i];
                next if (!$in{$fn});
                next if ($in{$fn} eq '');
                $cond .= " And " if ($cond);
                if ($i == 0) {
                        $cond .= "$fn = $in{$fn}";
                }
                else {
                        $cond .= "$fn = \'$in{$fn}\'";
                }
        }
        $sql = "SELECT * FROM [$table]";
        if ($cond) {
                $sql .= " WHERE " . $cond;
        }
        if ($O->Sql($sql)) {
                exitError('Sql()が失敗しました: '.$O->Error()."\n".$sql);
                $O->Close();
        }

print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
<SCRIPT language="JavaScript">
<!--
function selectID(form)
{
END_OF_HTML_1
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print "\t".
                        'top.Lower.document.forms[0].elements['.$i.'].value = '.
                        'form.elements['.$i.'].value;'."\n";
        }

print <<END_OF_HTML_2;
}
//-->
</SCRIPT>
</HEAD>
<BODY>
<!--FORM name="Data"-->
<TABLE>
END_OF_HTML_2

        print "<TR>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                my($fn) = $FieldNames[$i];
                print '<TH valign="left" nowrap>'.$fn."</TH>\n";
                push(@hidden, '<INPUT type="hidden" name="'.$fn.'" value="'.$in{$fn}.'">'."\n");
        }
        print "</TR>\n";

        # 行レコードの取得
        while($O->FetchRow()){
                undef %Data;
                %Data = $O->DataHash();
                print "<FORM>\n";
                print "<TR>\n";
                for ($i=0; $i < scalar(@FieldNames); $i++) {
                        $d = $Data{$FieldNames[$i]};
                        $d = ($i==0) ?
                                '<INPUT type="button" name="Col-'.$i.'" value="'.$d.'" onClick="selectID(this.form)">' :
                                '<INPUT type="hidden" name="Col-'.$i.'" value="'.$Data{$FieldNames[$i]}.'">'.$d;
                        print '<TD NOWRAP BGCOLOR="#D0D0D0">'.$d."</TD>\n";
                }
                print "</TR>\n";
                print "</FORM>\n";
        }
        print "</TABLE>\n";

        print "<FORM action=\"$CGIPath/$Program\" name=\"Update\">\n";
        print @hidden;
        print '<INPUT type="hidden" name="Action" value="getData">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print "</FORM>\n";

        print "</BODY>\n";
        print "</HTML>\n";

        # ODBC コネクションのクローズ
        $O->Close();
}


#
# <IN>  なし
# <OUT> なし
#
sub viewField
{
        my(@table, $table);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # SQL の発行
        if ($O->Sql("SELECT * FROM [$table]")) {
                exitError('Sql()が失敗しました: '.$O->Error());
        }
        @FieldNames = $O->FieldNames();

print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
</HEAD>
<BODY>
<TABLE>
END_OF_HTML_1

        print "<TR>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print '<TH valign="left" nowrap>'.$FieldNames[$i]."</TH>\n";
                push(@hidden, '<INPUT type="hidden" name="'.$FieldNames[$i].'" value="">'."\n");
        }
        print "</TR>\n";

        print "</TABLE>\n";

        print "<FORM action=\"$CGIPath/$Program\" name=\"Update\">\n";
        print @hidden;
        print '<INPUT type="hidden" name="Action" value="getData">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print "</FORM>\n";

        print "</BODY>\n";
        print "</HTML>\n";

        # ODBC コネクションのクローズ
    $O->Close();
}

#
# <IN>  なし
# <OUT> なし
#
sub viewQueryField
{
        my(@table, $talbe);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # SQL の発行
        if ($O->Sql("SELECT * FROM [$table]")) {
                exitError('Sql()が失敗しました: '.$O->Error());
        }
        @FieldNames = $O->FieldNames();

print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
<SCRIPT language="JavaScript">
<!--
function sendData(act)
{
        document.Field.Action.value = act;
        document.Field.submit();
}

function searchData()
{
        for (i in document.Field.elements) {
                n = document.Field.elements[i].name;
                v = document.Field.elements[i].value;
                for (j in top.Upper.document.Update.elements) {
                        if (top.Upper.document.Update.elements[j].name == n) {
                                top.Upper.document.Update.elements[j].value = v;
                                break;
                        }
                }
        }
        top.Upper.document.Update.submit();
}
//-->
</SCRIPT>
</HEAD>
<BODY>
END_OF_HTML_1

        print "<FORM name=\"Field\" action=\"$CGIPath/$Program\">\n";
        print "<TABLE>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print "<TR>\n";
                print '<TD>'.$FieldNames[$i]."</TD>\n";
                print '<TD><INPUT type="textarea" name="'.$FieldNames[$i].'" size="36"></TD>'."\n";
                print "</TR>\n";
        }
        print "</TABLE>\n";
        print '<INPUT type="hidden" name="Action" value="">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print '<INPUT type="button" name="Search" value="検索" onClick="searchData()">'."\n";
#       print '<INPUT type="button" name="Modify" value="変更" onClick="sendData(\'modifyData\')">'."\n";
        print '<INPUT type="button" name="Add" value="新規登録" onClick="sendData(\'addData\')">'."\n";
        print '<INPUT type="button" name="Delete" value="削除" onClick="sendData(\'deleteData\')">'."\n";
        print '<INPUT type="reset" name="Clear" value="クリア">'."\n";
        print "</FORM>\n";

        print "</BODY>\n";
        print "</HTML>\n";

        # ODBC コネクションのクローズ
    $O->Close();
}


#
# <IN>  なし
# <OUT> なし
#
sub modifyData
{
        my(@table, $talbe);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # SQL の発行
        if ($O->Sql("SELECT * FROM [$table]")) {
                exitError('Sql()が失敗しました: '.$O->Error().
                        "\n"."SELECT * FROM [$table]");
        }
        @FieldNames = $O->FieldNames();
        $firstf = $FieldNames[0];               # 'ID' field
        for ($i=1; $i < scalar(@FieldNames); $i++) {
                $set = $set."$FieldNames[$i] = \'$in{$FieldNames[$i]}\',";
        }
        chop($set);
        if ($O->Sql("UPDATE $table SET $set WHERE ID = $in{$firstf}")) {
                exitError('Sql()が失敗しました: '.$O->Error().
                        "\n"."UPDATE $table SET $set WHERE ID = $in{$firstf}");
        }

print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
<SCRIPT language="JavaScript">
<!--
function update()
{
        top.Upper.document.Update.submit();
}
function sendData(act)
{
        document.Field.Action.value = act;
        document.Field.submit();
}
//-->
</SCRIPT>
</HEAD>
<BODY onLoad="update()">
END_OF_HTML_1

        print "<FORM name=\"Field\" action=\"$CGIPath/$Program\">\n";
        print "<TABLE>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print "<TR>\n";
                print '<TD>'.$FieldNames[$i]."</TD>\n";
                print '<TD><INPUT type="textarea" name="'.$FieldNames[$i].'" size="36"></TD>'."\n";
                print "</TR>\n";
        }
        print "</TABLE>\n";
        print '<INPUT type="hidden" name="Action" value="">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print '<INPUT type="button" name="Search" value="検索" onClick="searchData()">'."\n";
#       print '<INPUT type="button" name="Modify" value="変更" onClick="sendData(\'modifyData\')">'."\n";
        print '<INPUT type="button" name="Add" value="新規登録" onClick="sendData(\'addData\')">'."\n";
        print '<INPUT type="button" name="Delete" value="削除" onClick="sendData(\'deleteData\')">'."\n";
        print '<INPUT type="reset" name="Clear" value="クリア">'."\n";
        print "</FORM>\n";
        print "</BODY>\n";
        print "</HTML>\n";

        # ODBC コネクションのクローズ
    $O->Close();
}


#
# <IN>  なし
# <OUT> なし
#
sub addData
{
        my(@table, $table);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # SQL の発行
        if ($O->Sql("SELECT * FROM [$table]")) {
                exitError('Sql()が失敗しました: '.$O->Error());
        }
        @FieldNames = $O->FieldNames();

        # ID の最大値を求める
        my($sql) = "SELECT MAX\($FieldNames[0]\) FROM [$table]";
        if ($O->Sql($sql)) {
                exitError('Sql()が失敗しました: '.$O->Error()."\n"."$sql");
        }

        # SQL の発行
        $O->FetchRow();
        $in{$FieldNames[0]} = $O->Data() + 1;
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                $values = $values."\'$in{$FieldNames[$i]}\',";
        }
        chop($values);
        if ($O->Sql("INSERT INTO $table VALUES($values)")) {
                exitError('Sql()が失敗しました: '.$O->Error().
                        "\nINSERT INTO $table VALUES($values)");
        }


print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
<SCRIPT language="JavaScript">
<!--
function update()
{
        top.Upper.document.Update.submit();
}
function sendData(act)
{
        document.Field.Action.value = act;
        document.Field.submit();
}
//-->
</SCRIPT>
</HEAD>
<BODY onLoad="update()">
END_OF_HTML_1

        print "<FORM name=\"Field\" action=\"$CGIPath/$Program\">\n";
        print "<TABLE>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print "<TR>\n";
                print '<TD>'.$FieldNames[$i]."</TD>\n";
                print '<TD><INPUT type="textarea" name="'.$FieldNames[$i].'" size="36"></TD>'."\n";
                print "</TR>\n";
        }
        print "</TABLE>\n";
        print '<INPUT type="hidden" name="Action" value="">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print '<INPUT type="button" name="Search" value="検索" onClick="searchData()">'."\n";
#       print '<INPUT type="button" name="Modify" value="変更" onClick="sendData(\'modifyData\')">'."\n";
        print '<INPUT type="button" name="Add" value="新規登録" onClick="sendData(\'addData\')">'."\n";
        print '<INPUT type="button" name="Delete" value="削除" onClick="sendData(\'deleteData\')">'."\n";
        print '<INPUT type="reset" name="Clear" value="クリア">'."\n";
        print "</FORM>\n";
        print "</BODY>\n";
        print "</HTML>\n";


        # ODBC コネクションのクローズ
    $O->Close();
}


#
# <IN>  なし
# <OUT> なし
#
sub deleteData
{
        my(@table, $table);
        my($dsn) = $in{'DSN'};

        # ODBC オブジェクトの生成
        if (!($O = new Win32::ODBC($dsn))) {
                exitError('ODBCオブジェクトが生成できません(DSN='.$dsn.")\n".
                        Win32::ODBC::Error());
        }

        # ODBC コネクションのオープン
        $O->Connection();

        # テーブル名の取得
        foreach ($O->TableList("", "", "%", "TABLE, VIEW, SYSTEM_TABLE")){
                push(@table, $_);
                if ($in{'TableName'} eq $_) {
                        $table = $_;
                        break;
                }
        }
        if (!$table) {
                exitError("テーブルがありません: $in{'TableName'} [@table]");
        }

        # SQL の発行
        if ($O->Sql("SELECT * FROM [$table]")) {
                exitError('Sql()が失敗しました: '.$O->Error());
        }
        @FieldNames = $O->FieldNames();

        # ID の最大値を求める
        $firstf = $FieldNames[0];
        $sql = "DELETE * FROM [$table] WHERE $firstf = $in{$firstf}";
        if ($O->Sql($sql)) {
                exitError('Sql()が失敗しました: '.$O->Error()."\n".$sql);
        }

print <<END_OF_HTML_1;
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$CharSet">
<TITLE>$Title</TITLE>
<SCRIPT language="JavaScript">
<!--
function update()
{
        top.Upper.document.Update.submit();
}
function sendData(act)
{
        document.Field.Action.value = act;
        document.Field.submit();
}
//-->
</SCRIPT>
</HEAD>
<BODY onLoad="update()">
END_OF_HTML_1

        print "<FORM name=\"Field\" action=\"$CGIPath/$Program\">\n";
        print "<TABLE>\n";
        for ($i=0; $i < scalar(@FieldNames); $i++) {
                print "<TR>\n";
                print '<TD>'.$FieldNames[$i]."</TD>\n";
                print '<TD><INPUT type="textarea" name="'.$FieldNames[$i].'" size="36"></TD>'."\n";
                print "</TR>\n";
        }
        print "</TABLE>\n";
        print '<INPUT type="hidden" name="Action" value="">'."\n";
        print '<INPUT type="hidden" name="DSN" value="'.$dsn.'">'."\n";
        print '<INPUT type="hidden" name="TableName" value="'.$table.'">'."\n";
        print '<INPUT type="button" name="Search" value="検索" onClick="searchData()">'."\n";
#       print '<INPUT type="button" name="Modify" value="変更" onClick="sendData(\'modifyData\')">'."\n";
        print '<INPUT type="button" name="Submit" value="新規登録" onClick="sendData(\'submitData\')">'."\n";
        print '<INPUT type="button" name="Delete" value="削除" onClick="sendData(\'deleteData\')">'."\n";
        print '<INPUT type="reset" name="Clear" value="クリア">'."\n";
        print "</FORM>\n";
        print "</BODY>\n";
        print "</HTML>\n";

        # ODBC コネクションのクローズ
    $O->Close();
}

#--End of odbc.cgi

Win32::ODBC のほかに、DBI::ODBC というものもあります。

http://www.hermetica.com/technologia/DBI/

DBIパッケージはいろいろなDBMSに接続できるモジュールがあります。



ファイル一覧

cgi-bin/odbc.cgi
cgi-bin/lib/util.pl

docs/Samples/odbc_access.html
docs/Samples/odbc_up.html
docs/Samples/odbc_low.html