2009-12-24

ODBC ドライバ DataDirect SequeLink を使って FileMaker Pro にアクセスしたときの問題点

 FileMaker Pro 対応の ODBC ドライバは DataDirect SequeLink となっていますが、今回はこのドライバを使って FileMaker Pro にアクセスした場合の問題点について書いていきます。

備考:
1. php から ODBC 接続する方法として PDO を使っています。PDO を有効にするには、php.ini の以下の行を追加し、Web サーバを再起動しておく必要があります。

  extension=php_pdo.dll
  extension=php_pdo_odbc.dll

2. PDO ではシステム DSN を指定する必要があるため、SequeLink ドライバを指定して適当な名前のシステム DSN を事前に登録しておく必要があります。
php ソースの記述例は次のとおりです。
//$dbh = new PDO ("odbc:DSN=データソース名;UID=ユーザー名;PWD=パスワード");

try {
     $pdo = new PDO("odbc:dsn=test;host=127.0.0.1", "Admin", "somePWD");
 $sql = "select * from testdb where recno=1";
 $rec = $pdo->query($sql);
               //レコードセットから特定の列を取りだすときは bindColum を使用
 $rec->bindColumn("ID", $ID);
     $rec->fetch();

 echo $ID;

} catch(PDOException $e){
    var_dump($e->getMessage());
}

 上記のような php スクプトを連続操作を実行すると、ODBC ドライバの動作が不安定になることがわかりました。
 
 返されたエラーは次のとおりです。

1) Session refused by service, connection closed.

 このエラーはサーバプロセスが接続要求を受理できなかったときに発生します。
 このエラー発生後、FileMaker Pro ファイルを閉じたり、一度 Windows をログオフしたりしたのですが、それでも現象が改善せず、マシンを再起動することによってようやく復旧しました。

2) Maximum number of sessions reached.

 このエラーは設定済のアクティブセッション数を超過した場合に発生し、その後のクライアント接続要求は拒否されてしまうようです。
 このエラー発生後、ファイルメーカー Pro ファイルを一度閉じることによって復旧しました。

 以下のサイトにエラーコードの一覧が用意されていますので、その他のエラー内容と原因も参照できます。
SequeLink のエラーメッセージ一覧

 ただ、これだけ動作が不安定だと、ODBC 接続実験としては面白いですが、とても運用レベルには耐えられないという印象です。また、CD に付属の SequeLink は 64bit 対応ではないため、別途購入する必要がある(しかも金額不明)というのも利用者を遠ざける原因になってしまうかもしれません。
SequeLink® 5.5 Client for ODBC 製品紹介ページ


ODBC 接続に関する続きの記事はこちら:
API 別/サーバ別FileMaker カスタムWebパフォーマンス比較

2009-12-22

IIS の php から FileMaker Pro ファイルをオープンするのに四苦八苦

 Windows Server 2003 の IIS で php ファイルから FileMaker Pro ファイルを開くという操作を試しているのですが、どうもうまくいきません。

【目標】
 IIS で公開されている test.php というファイルからサーバディスクに配置した dbopen.vbs を起動し、vbs から FileMaker Pro ファイル test.fp7 を開く。

dbopen.vbs の中身は次のとおりです。ここでは、FileMaker Pro アプリケーションのインスタンスを作成し、それからローカルコンピュータの test.fp7 を開いて showMSG というスクリプトを実行するという流れになっています。このファイルを作って単独で実行すると正常に動作することは確認済みです。


Dim FMApp
Dim FMDocs, myOpenFile

Set FMApp = CreateObject("FMPRO.Application")
FMApp.Visible = True
Set FMDocs = FMApp.Documents
Set myOpenFile = FMDocs.Open("c:\hoge\test.fp7" ,"Admin","somePwd")
myOpenFile.DoFMScript ("showMSG")

Set myOpenFile = Nothing
Set FMDocs = Nothing
Set FMApp = Nothing



【試した操作】
1. IIS 経由で php を実行すると、その実行者は IUSR もしくは NETWORK SERVICE になるため、実行権限を必要なファイル群に与える必要があります。dbopen.vbs は WScript.exe から起動させるため、System32 ディレクトリの中にある WScript.exe に IUSR の実行権限を付与しました。
2. これだと dbopen.vbs で CreateObject を使って FileMaker のインスタンスを作成する時に書き込みエラーが発生するため、IUSR ではなく、ログイン中のユーザアカウントで実行できるよう、PsTools の psexec.exe を使って vbs のみログインユーザ権限で実行するようにしました。

PsTools の紹介とダウンロードはこちら

以下のように test.php のソースに指定しました。


$retval = `C:\hoge\PsTools\psexec.exe -u Administrator -p somePassword1234 -d WScript.exe C:\hoge\dbopen.vbs`;


備考:
1. psexec.exe に IUSR アカウントを割り当て、実行権限を付与しておく必要があります。
2. ``で囲ったコマンドラインがシェルコマンドとして解釈されるため、ここでは exec()関数を使用していません。
3. -d はスクリプトの終了を待たずに psexec を終了させるためのスイッチです(異常終了時のプロセス残留回避)。
4. vbs ファイルは単体では認識されないため、WScript.exe を明示的に指定する必要があります。

 このように設定してから Web ブラウザより test.php を実行すると、ブラウザが読み込み中状態となってしまいます。そこでタスクマネージャを起動して確認してみると、実行者 NETWORK SERVICE のプロセスとして psexec.exe が残っていることがわかりました。

【現象】
 psexec の実行ユーザが NETWORK SERVICE になっていると、デスクトップにそのアプリケーションが表示されず、バックグランドプロセスとして残留してしまいます。
 二台の Windows Server 2003 環境で実行したところ、一台は test.fp7 がデスクトップに表示され、showMSG スクリプトまで表示されたのですが、もう一台のマシンがどうもうまくいきません。

 psexec に NETWORK SERVICE を割り当てて実行権限を付与したり、IIS マネージャのアプリケーションプールのセキュリティアカウントを NETWORK SERVICE 以外に設定するなど試したのですが、やはりプロセスがバックグランドで残留したままの状態となります。


 IIS で運用中の php スクリプトからシェルコマンドでアプリケーションを起動し、そのアプリケーションをデスクトップに表示させる方法をご存じの方は、情報をお待ちしております。

2009-12-11

FileMaker V10による在庫管理、一考

久々のFileMaker(以下、FM)の話題。
V9以前のFMでは、在庫を算出する場合は、在庫テーブルで以下のようにやっていたのではないだろうか?

在庫::在庫(計算) = 在庫::前月分在庫 - Sum(出庫明細::出庫数) + Sum(入庫明細::入庫数)


このやり方は簡単でいいのだけれど、出庫明細や入庫明細のレコード数が多いと、1つの商品の在庫の算出にさえ、数十秒から数分の時間がかかってしまう可能性がある。 よって、商品数と伝票枚数(商品取引)が多く、リアルタイムの在庫を即時把握したいような業種では、FMは使えなかった。
言い換えると、在庫や各種残高算等、あるテーブル(上例では、出庫明細、入庫明細)のフィールド値に基づき計算を行いその結果を他テーブルの(計算フィールドではない)フィールドに精度を確保しながら保存する、ということができないということは、1995年のV3リリース以来、FMの長年の弱点の一つであった。

そんなところにFM V10が現れたのは一年程前だったか。 このバージョンでFMはイベント発生時のスクリプト起動(以下、スクリプトトリガ)に対応した。 スクリプトトリガ、特に、レコード保存時にスクリプトを実行する「OnRecordCommit」により、上記の弱点が解消される可能性がでてきたように思われる。
以下、その原案。

1. 想定(目標)
以下のような簡単な在庫管理データベースがあり、出庫伝票作成時に各商品の出庫数を在庫数から差し引くことを目的とし、その実装(スクリプト)を考えてみる。
尚、出庫伝票は新規作成のみであり、明細の更新は不可(ホンナ無茶な)とする。

【図1】


【図2】

図1の出庫伝票で、[出庫数]に入力をしレコードを保存する動作を行った時に、在庫リストの[在庫数]の値が[出庫数]を差し引いた値に更新されればいい。 但し、このとき在庫リストの[在庫数]は計算ではなく、数値フィールドである、というのが今回の肝である。


2.実装
まずレコードを保存(Commit)時に在庫テーブルの[在庫数]フィールドから[出庫数]を差し引くスクリプトが必要である。

【図3】


という具合に、出庫明細を1行づつ移動して、関連する在庫レコードの[在庫数]から[出庫数]を差し引き、[在庫数]にセットする。 途中あるエラー処理は、[出庫数]更新時にエラーが発生した場合、このスクリプトで行ったすべての処理を取り消し、レコードを最後に保存した状態に戻すためのものである。

では、ユーザの操作(クリック)に依存せず、レコード保存(Commit)時に必ずこのスクリプトを実行するにはどうしたらよいか? ここでFM V10の新機能、スクリプトトリガの「OnRecordCommit」を使用する。 詳細はマニュアルを見ていただくとして、下図のように上記で作成したスクリプトを登録すればよい。

【図4】

以上で完了。


3.テスト
テストをしてみると、一応、機能する。
図1の出庫伝票入力後に保存を行うと、商品1~3の[在庫数]は正しく「9」に更新される。

また、[在庫数]更新時にエラーが発生すると、その出庫伝票が最後に更新されたときの状態に戻り、在庫レコードも元の状態に戻る。
たとえば、商品1と2の[在庫数]の更新には成功したが、商品3の[在庫数]の更新に失敗すると、すべての処理が取り消され、最後の保存状態に戻る。 このとき、出庫レコード自体が一度も保存されていなければ、明細レコードだけではなく、出庫レコードも保存されない(作成されない)筈である。 


4.課題
さて、上記のように当初の思惑は達成されたが、いくつかの課題と懸念がある。
  1. 今回は出庫伝票は新規のみである、ことを前提としているが、当然、これでは実用には耐ええない。出庫明細の更新、削除にも対応する必要がある。
  2. 在庫テーブルで極力競合が発生しないようにテーブル設計する必要がある。
  3. 十分なテスト --- マルチユーザで競合が発生しないこと、また競合発生時も整合性が確保されること。
  4. 上記実装が正しく機能しているか、検証する仕組みの構築

1.は面倒だか、明細の主キー、商品ID、更新前の[出庫数]と更新後の[出庫数]の差分を変数に記憶しておき、Commit時に個々の商品の[在庫数]からその差分を減算すれば、解決可能である。

クリティカルな環境で上記のような在庫ロジックを実装し、実際の運用まで持ち込むのはなかなか大変だと思われるが、在庫や残高の算出遅延が運用上のネックとなっているシステムでは、一考の価値があるのではなかろうかと。

以上

土屋


【関連リンク】

2012/8/1追記:
当社の在庫管理の講習で使用してるサンプルシステム「FMEasy在庫」を公開しました。フリー版/開発版のダウンロードは→こちら

【FMEasy在庫 の画面】