ushidayの日記

主に「IBMi」のメモに・・・

暗黙スキーマの挙動の違い

PCからお手軽に、既存のIBM i(AS/400)のプログラムを呼び出す方法に、SQLのCALLを投げる方法があります。こんな感じで
■PC系の文法

CALL スキーマ名.プログラム名 ('引数','引数2')

AS/400の対話式SQL

CALL スキーマ名/プログラム名 ('引数','引数2')

通常自分は、ユーザーによって実行ライブラリが異なる可能性があるので、ライブラリ名(スキーマ名)を指定しません。スキーマ名を変数にしても良いのですが、AS/400の伝統的に暗黙のオープンというのがあります。暗黙オープンの方法としては...

  1. ユーザージョブの”ライブラリーリスト”に入れる。
  2. ”set schema ライブラリ名”をする。

が、考えられます。前者は、本番運用向きとは思いますが、開発の場合は環境毎にユーザーが変わるので、自分は後者の「set schema」を使っています。
この”暗黙のスキーマ”なのですが、PHPDB2関数で、微妙にAS/400とPCで挙動の違いが有ったので、メモをしておきます。

AS/400(Zend Core for i5 2.6.1)の場合は、”set schema”でスキーマを指定すれば、暗黙でプログラムをcall出来ます。しかし開発用PC(Zend Server CE 4.0)から発行されたSQLの場合には、次の様なメッセージが返されました。

call hoge ('fuga') SQL0204N  "ユーザ名.hoge" は未定義の名前です。  SQLSTATE=42704

PHPDB2関数かDB2 Connectなのか分かりませんが、暗黙のスキーマが見つからない場合は、自動でユーザー名を明示的スキーマに置き換えます。(間違って存在していて勝手にプログラムが動かれても困りますが...。)
今回は対応方法として、AS/400のプログラムをストアドプロシージャ定義する事にしました。方法は以下の通りです。

    • OPMプログラムならばILE化する。(OPMだとストアド情報の保管・復元が出来ないため)
    • ”create procedure”で、プログラムをストアド定義する。

■ストアド定義SQLの例(※CLプログラムで5バイト文字列の引数を1つ取る場合)

CREATE PROCEDURE スキーマ名/プロシージャ名(IN 引数名 CHAR (5 )) LANGUAGE CL
NOT DETERMINISTIC CONTAINS SQL EXTERNAL NAME ライブラリ名/プログラム名
PARAMETER STYLE GENERAL       
    • 実行時に”set path スキーマ名”で関数パスを指定して、プロシージャ名をcallで呼びだす。

OPMをILE化するのは、SAVLIBやRSTLIBでストアド定義の情報が反映されないからです。検証してわかったのですが、プログラムのリネームや削除、ライブラリのリネームをしてもストアド情報と同期はされません。プログラムをSAVOBJ,RSTOBJしても同様に、ストアド情報は同期されませんでした。但し、ライブラリを削除した時だけは、ストアド情報も消えるようです。ライブラリを保管→ライブラリ削除→ライブラリ復元だと、ストアド情報も同期された状態で、復元しました。この事から、ILEオブジェクトの何処かに、ストアドに関するメタ情報を持っていると思うのですが、何処にあるか見つける事が出来ませんでした。(DSPPGMなどには無かった)
※追記:その後、DMPOBJコマンドでメタ情報を確認出来ました。SQL文が丸ごと残ってます。
ちなみに、OPMでストアド定義すると、プロシージャは作成されますが、その旨の警告メッセージが出力されました。
■注意書き(※DB2 Universal Database for iSeries SQL 解説書より)

*PGM オブジェクトが保管された後、このシステムや別のシステムに復元すると、カタログはそれらの属性を使用して自動的に更新されます。
外部プロシージャーの場合は、次の制約の範囲内で属性を保管することができます。
・ 外部プログラム・ライブラリーは、QSYS であってはなりません。
・ 外部プログラムは、CREATE PROCEDURE ステートメントの発行時に存在していなければなりません。
・ 外部プログラムは、ILE *PGM オブジェクトか*SRVPGM オブジェクトにする必要があります。
オブジェクトを更新できない場合でも、それにかかわらず、プロシージャーは作成されます。

これでプロシージャ名を呼び出せば、AS/400でもPCでも暗黙的にプログラムを呼び出す事が出来ます。
但しこの場合は、プログラム名の呼出と違って、AS/400でも”set path”で関数パスを指定する必要があります。ちなみに、ジョブのライブラリーリストに入っていれば、”set path”は不要です。本番運用ならばライブラリーリストでやるのが、一番楽チンかもしれませんネ。

ストアドプロシージャ定義の一覧を確認するには、次のSQLを投げると確認出来ます。

 select * from sysroutines where specific_schema = 'スキーマ名'