Postgres・MDB2のキャスト演算子とプレースホルダ
月花です。
PDOによるデータベース操作の話をします。
今回はこんな話です
ことの発端
MDB2を使ったフレームワークで、Postgresから疑問符プレースホルダを使ったINSERTを行った際に、不思議なエラーが発生した。
INSERT INTO test (id,name,value) VALUES (1,NULL::TEXT,?);
こういうクエリをprepareして、
array('test')
を食わせてexecuteするような、一見問題のないINSERT文を実行した。
すると、
〜〜〜 MDB2 Error: unknown error 〜〜〜 [Native message: ERROR: 入力の最後で 構文エラー LINE 1: INSERT INTO test (id,name,value) VALUES (1,NULL$1
とのこと。
不思議なエラー文だ。
糸口を探る
[Native message: ERROR: 入力の最後で 構文エラー LINE 1: INSERT INTO test (id,name,value) VALUES (1,NULL$1
ということで、$1がどうにも気になる。
これはたぶん、プレースホルダだ。
原文では、NULLがベタ書きされている箇所は一個しか無いので、そうすると
NULL::TEXT
が気になってきた。
もしかして
INSERT INTO test (id,name,value) VALUES (1,CAST( NULL AS TEXT ),?);
コロンでのキャスト演算子ではなく、こうなら・・・・
いけた。
ということは、
- コロン2つによるキャストが影響している
- どうも不当にプレースホルダとして解釈されている
- コロンを使わなければ治る
となれば原因は
結局は、
INSERT INTO test (id,name,value) VALUES (1,NULL::TEXT,?);
この、 NULL::TEXT の、 :TEXT が名前付きプレースホルダとして解釈され、 NULL$1 となり、さらに元々の疑問符プレースホルダとの競合もあり、構文エラーとなったようである。
ところが、これそんなはずはなく、正しい文法のはずだ。
ためしにいくつかのSQLクライアントから、疑問符プレースホルダを適当な値に変換したものを実行したが、どれも成功した。
ということは、フレームワーク・・・と思ったがこいつはMDB2との橋渡しをしているだけだ。
というわけでMDB2を探っていく。
環境の再現
適当な VirtualBox でMDB2をインストールして、下記のような環境にした。
# pear list Installed packages, channel pear.php.net: ========================================= Package Version State Archive_Tar 1.4.2 stable Console_Getopt 1.3.1 stable MDB2 2.4.1 stable MDB2_Driver_pgsql 1.4.1 stable PEAR 1.9.5 stable Structures_Graph 1.0.4 stable XML_RPC 1.5.4 stable XML_Util 1.2.3 stable
これで、さくっと書いて実行する。
require_once 'MDB2.php'; $dsn = 'pgsql://***:***@***/***'; $options = array( 'debug' => 2, 'result_buffering' => false, ); $mdb2 = MDB2::connect($dsn); if (PEAR::isError($mdb2)) { die($mdb2->getMessage()); }else{ $sql="INSERT INTO test (id,name,value) VALUES (1,NULL::TEXT,?);"; $statement=$mdb2->prepare($sql); if (PEAR::isError($statement)){ echo $statement->getDebugInfo(); }else{ $statement->execute(array('test')); } } $mdb2->disconnect();
とすると、やはり同じエラーが出た。
ということで、MDB2が悪いことが確定して一安心。
解決
そもそも、キャスト演算子がコロンでできている以上、検索のしにくさったら。
過去の例が全然見当たらない。
こういうときはとりあえずバージョンアップをしてみよう。
# pear install MDB2-2.5.0b5 # pear install MDB2_Driver_pgsql-1.5.0b4 # # pear list Installed packages, channel pear.php.net: ========================================= Package Version State Archive_Tar 1.4.2 stable Console_Getopt 1.3.1 stable MDB2 2.5.0b5 beta MDB2_Driver_pgsql 1.5.0b4 beta PEAR 1.9.5 stable Structures_Graph 1.0.4 stable XML_RPC 1.5.4 stable XML_Util 1.2.3 stable
とすると、あっさり成功したのでした。
なので、MDB2のChangeLogを読み漁る。
すると、MDB2_Driver_pgsql 1.5.0a1 において、
Changelog: 〜〜〜 - fixed bug #11652: failed prepared queries containing the "::type" style of casting 〜〜〜
なんと、2007-07-20 12:38 UTC に報告された不具合である。
10年前て・・・