嵌りました。。。orz
かなり特殊な状況ではあるのですが、同じ落とし穴に他の人が嵌らないよう、メモ。
使用しているバージョンは
PHP:5.2.6
PEAR、MDB2:現時点で最新
PostgreSQL:7.4系
で、問題は、PEARマニュアル
http://pear.php.net/manual/ja/package.database.mdb2.intro-execute.php
にある、「例 39-2execute() に配列を渡す」の要領で
<?php //なんか適当なINSERT文をprepareしてるとして $affectedRows = $sth->execute($data); var_dump($affectedRows);
としても、出力が
int(0)
・・・なぜ!?データベースの中身はちゃんと更新されてるのに!!
で、いろいろ調べてたら、なんか奇妙な事実が次々とでてきた。
- DML文はどれを実行しても(INSERT/UPDATE/DELETE)、0が返る。エラーにはならない。データベースもちゃんと更新されている。
- プリペアードステートメントを使わず、直接 $sth->exec() した場合はちゃんと取得できる
これはもう挙動を追うしかないなぁ。。。と思い、MDB2のソースを探索。
う〜ん・・・execute()もexec()も最終的に行き着くところ同じなんだ。。。
だとすると、余計この2つで挙動が違うのか理解できない。。。
PostgreSQLがPREPAREをサポートしてないバージョン?
・・・いや、7.4からサポートだから、それは大丈夫なはず。。。
PHPのpg_prepare()関数も、5.1以降だから条件は満たしてるはず。。。
でもなんか妙に気になったので、試しにこのコードを実行してみた:
<?php var_dump(function_exists('pg_prepare')); //出力結果 //bool(false)
・・・・はぁ!?.。ooO(゚ぺ/)/
なぜ?なぜ?
PHPもPostgreSQLもバージョン条件は満たしてるのに。。。
更に気になったので。。。
<?php var_dump(function_exists('pg_execute')); var_dump(function_exists('pg_query_param')); //出力結果 //bool(true) //bool(true)
はへっ!?
なんじゃこりゃ。。。わけわからん。。。(x_x)
どうやら、pg_prepare()だけが使えない模様。
う〜ん、これはどうもPHPのコンパイルオプションとか絡んでそうだな。。。
あと、PostgreSQLのライブラリのインクルードがどうとか。。。
ちょっとそっちを追いかけるのは後にしてと。
この、pg_prepare()が使えない、という前提で、もう一度MDB2をコードリーディング。
なるほどね。わかった。
どうやら、MDB2内部ではこんな風になってるらしい。
- pg_prepare()関数があれば、それを使う
- pg_prepare()がなくて、PostgreSQLがPREPARE構文をサポートするなら、pg_query()でPREPARE構文を使用する
- それもだめなら、MDB2でエミュレート
で、問題はこの2番目。
pg_query()関数を使って、PREPARE/EXECUTE構文をSQLとして発行する場合、pg_affected_rows()関数が影響行数を返さないんじゃないか疑惑浮上。
(MDB2のexecute()メソッドの返値は、追っかけると最終的にpg_affected_rows()関数を呼び出しているので)
そこで実験。
<?php $conn = pg_connect(DB_CONN_STRING);//DB_CONN_STRING は正しいDB接続文字列を格納した定数とする。 $sql_prepare = 'PREPARE test_stmt(text) AS INSERT INTO hoge VALUES ($1) '; pg_query($conn, $sql_prepare); $sql_execute = "EXECUTE test_stmt('fuga')"; $res = pg_query($conn, $sql_execute); $affectedRows = pg_affected_rows($res); var_dump($affectedRows);
出力結果:
int(0)
ビンゴだ。。。
わかったことを整理すると。
- pg_affected_rows()関数は、PREPARE/EXECUTE構文をpg_query()関数で直接呼び出した場合には、影響行数を返さず、常に0を返す
- MDB2は、pg_prepare()が使えないと、PREPARE/EXECUTE構文を使おうとする。
これが原因で、AffectedRowsが取得できなかったのか。。。
しかし、「(PHP/PostgreSQLのバージョン条件は満たしてるのに)なぜ pg_prepare()関数が未定義か? 」については未解決。。。
これはもう少し深いところ追いかけないとわからなそうだ。。。orz