[PHP-users 27769] Re: PEAR DBでPL/SQL使えますか?

shin-1@ca2.so-net.ne.jp shin-1 @ ca2.so-net.ne.jp
2005年 12月 7日 (水) 05:13:15 JST


  お世話になります。nomotoです。

できました!ありがとうございます。その後の試行錯誤の経緯をご報告します。

>DB_common::prepare()とexecute()の組み合わせで可能です。
>ストアドとのやりとりにはPEAR_DBのプレースホルダを使用して、
>execute()のパラメータで渡してやれば大丈夫です。
>(ストアドのout変数はPHPからリファレンスを渡しておかないと
> 駄目かも)
>
>このへん、参考になると思います。OCI関数ですが。
>http://kamakura.cool.ne.jp/oppama/oswa/phpocicallsp.html
>あとはPEAR_DBのoci8.phpを追っかけてみるのもいいでしょう。

そうか!PROCEDUREで検索してたから情報も見つからなかったのですね。
まずはPEARでも呼び出せる事がわかり一安心。「PEAR ストアド」でググってみたら
>[PHP-users 9380] PEAR + Oracleでストアドプロシージャを実行できない
などの過去記事も出てきました。

で、declare begin test001.aaa('a', 'b', '', '', ''); end
というSQL文を実行してみたところ、test001.aaaはプロシージャとして定義
されていないというORAエラーが出たので、test001.aaaを使っているCソース
を見てみると declare begin :wkret := test001.aaa('a', 'b', '', '', ''); end
というなっていました。これってファンクションですね(汗)

またCのソースみてみると、3番目〜5番目はOracleからのエラーを拾うための
パラメータらしく :sys_ora_msg:ind_msg, :sys_ora_ecd:ind_emsg, :sys_ora_emsg:ind_ecd,
となっていました。このあたりも変数にBindしないとだめみたい。

という事で、PEAR DB のソースを追っかけてバインドの実装はどうなっている
かを確認しました。
oci8.phpを見ると、プレースホルダ「?」は出現順に :bind0 :bind1 という
文字列に置き換えたうえで、executeで渡したパラメータを順番に
 OCIBindByName($stmt, ":bind0", $data[$i], -1); という具合にバインドして
いる様子でしたので、executeの第2引数に&$msgという形で変数参照を渡せば、
リファレンスであってもSQL文中の?にうまくバインドしてくれそうです。

$stmt = $con->prepare("declare begin ? := test001.aaa('a', 'b', ?, ?, ?); end");
$ret = $con->execute($stmt, Array(&$wkret, &$omsg, &$oecd, &$oemsg));
とやってみましたが、今度はストアドは実行されたのですが、
>ORA-06502: PL/SQL: 数値または値のエラー: 文字列バッファが小さすぎます。
が帰ってきました。ストアド側で値に入るときにPHPの変数領域が拡張されない
ようですね。
それなら!と、Bindする変数に先に空文字を256バイトつっこんでみると
今度はうまくいきました!最終的なソースはこちら。

$wkret = 0;
$omsg = str_pad('', 256);
$oecd = 0;
$oemsg = str_pad('', 256);
$stmt = $con->prepare("declare begin ? := test001.aaa('a', 'b', ?, ?, ?); end");
$ret = $con->execute($stmt, Array(&$wkret, &$omsg, &$oecd, &$oemsg));

実際は'a'や'b'もバインドしています。

情報が少なかったので、ほんと助かりました。ありがとうございました。



PHP-users メーリングリストの案内