yTakeです。今回はSQLでBLOB型データの更新方法について、質問させて下さい。
既に登録されているレコード上のBLOB型データへ画像を登録・更新する事を考えます。
単純に、UPDATE分で、WHERE句でレコードを限定した上で、BLOB型のフィールドに画像データファイル名を渡すだけではダメでした。
当Q&Aの過去や他の参考サイトを参照して、下記2案を考えましたが、いずれもうまく行っていません。
案1:
bmp : TBitMap;
stream : TStream;
stream := IBQuery2.CreateBlobStream( IBQuery2.FieldByName( 'image' ), bmWrite );
bmp := TBitMap.Create();
とした上で、
sql_cmd := 'SELECT * from TBL where ID = ''' + id + ''' and NAME = ''' + name + '''';
IBQuery2.SQL.Text := sql_cmd;
IBQuery2.Open();
if IBQuery2.IsEmpty = True then
Showmessage( 'Empty' )
else
begin
cnt := 0;
while IBQuery2.Eof = False do
begin
IBQuery2.Edit();
bmp.LoadFromFile( portrait_file );
bmp.SaveToStream( stream );
IBQuery2.Post();
inc( cnt );
end;
end;
としてみましたが、access violationです。但しこれは、SELECT文の応答が無限ループになってしまっている為の様です。このSELECT文自体は、他の箇所で用いている場合と全く同じで、正しくSELECT出来ています。なぜ、ここではその応答が無限ループになってしまうのでしょう?他のやり方でレコードを限定するのでしょうか?
案2:
bmp : TBitMap;
blobStream : TIBBlobStream;
blobStream := TIBBlobStream.Create();
blobStream.Database := IBDatabase2;
// blobStream. ここで、テーブルを指定したい
blobStream.FieldAddress( 'PORTRAIT' );
とした上で、
if IBQuery2.IsEmpty = True then
ShowMessage( 'Empty' )
else
begin
cnt := 0;
while IBQuery2.Eof = False do
begin
IBQuery2.Edit();
bmp.LoadFromFile( portrait_file );
bmp.SaveToStream( blobStream );
IBQuery2.Post();
end;
end;
とすれば良いのかな?と思いますが、blobStreamのCreate時点で引数が何もないので、データベースやテーブルの指定ができません。その後で個別に設定しようと思いましたが、テーブルの指定が分かりません。
ここでも、案1の様なSELECT分の応答の無限ループ問題が発生するかもしれませんが、、、
インターネット上の例とは、なぜか引数の指定が違っているので、苦慮しています。
いずれの案も"try finally"節で、ストリームを開放しています。
いずれがより良いのか?又、エラーの回避方法に何か示唆を頂ければ幸いです。
環境は、
Windows7 (bootcamp),
Embedded Firebird v2.5, DELPHI XE3 + IBX,
です。
よろしくお願い致します。
普通にUPDATE分を使ってBLOBフィールの更新部分はパラメータクエリにしたら良いんじゃ無いんでしょうか?
UPDATE TABLE1 SET BLOB1=:BLOB WHERE ID=:ID;
IBQuery1.ParamByName('BLOB').LoadFromFile(File)
IBQuery1.ParamByName('ID').AsInteger := ID;
auさん
ありがとうございます。
Replyが遅くなりすみません。
そうですか。UPDATE文でBLOB型データも更新可能と言う事ですね。
すると、上記ですとUPDATE文のすぐ後で"IBQuery1.ParamByName('BLOB').LoadFromFile(File)"をじっこうしていますが、どういう意味でしょうか?
また、根本的な事とは思いますが、UPDATE文のなかで':'が使われています。':'の意味は何でしょうか?
私は使っていませんが、これまではそれなりに期待通りに操作できています。
調べてみましたが、明確に解説してある物を見つけられていません。
ご案内の通り試してみたつもりですが、EDataBaseError(パラメータ'PORTRAIT'が見つかりません)が発生します。
.ParamByName('フィールド名')と.FieldByName('フィールド名')、の違いも良く分かっていません。事実、"ParamByName"と"FieldByName"を入れ替えてみると、"FieldBuName"ではLoadFromFileが出てきません。
試してみたソースは次の通りです。
sql_cmd := 'UPDATE PATIENT_TBL SET PORTRAIT = ''' + portrait_file + ''' where ID = ''' + id + ''' and NAME = ''' + name + '''';
IBQuery2.SQL.Text := sql_cmd;
IBQuery2.ExecSQL();
IBQuery2.ParamByName( 'PORTRAIT' ).LoadFromFile( portrait_file, ftGraphic );
PORTRAITがデータベース上のBLOB型フィード
ID, NAMEは、DELPHI上の変数で、データベース上から検索すべきIDとNAMEを保持しています。
よろしくお願いします。
> また、根本的な事とは思いますが、UPDATE文のなかで':'が使われています。':'の意味は何でしょうか?
> 私は使っていませんが、これまではそれなりに期待通りに操作できています。
> 調べてみましたが、明確に解説してある物を見つけられていません。
[SQL インジェクション]
http://ht-deko.minim.ne.jp/delphiforum/?vasthtmlaction=viewtopic&t=1162
[IBConsole 日本語版+α ユーザーズガイド]
http://ht-deko.minim.ne.jp/software/ibconsole_ja_mod.pdf
DEKOさん
たいへんありがとうございました。
auさんにりぷらい頂いた時から、”パラメータクエリ”を正しく認識できていませんでした。”SQLインジェクション”も初めて聞きました。勉強不足です。
パラメータクエリの趣旨が良く分かりました。
資料を参照させえて頂き下記の様に修正しました。パラメータは認識されたのですが、次の問題が出現しています。
sql_cmd := 'UPDATE PATIENT_TBL SET PORTRAIT = :PORTRAIT WHERE ID = ''' + id + ''' and NAME = ''' + name + '''';
IBQuery2.SQL.Text := sql_cmd;
IBQuery2.ParamByName( 'PORTRAIT' ).LoadFromFile( portrait_file, ftGraphic );
IBQuery2.ExecSQL();
これを実行すると、"EIBClientErrorサポートされていない機能"が発生します。
これはどういうことでしょう?FlameRobinやIBConsoleなどでは、BLOB型へ画像を登録し参照する事は出来ています。
もしかして、デバッグ中はSuper Serverへ接続するはずが、Embedded Serverへ接続されているのか?とも思いましたが、IBDatabaseのDatabaseNameプロパティを表示させていますが、リモート接続を意味する"localhost:"で始まっています。
database := 'データベース本体へのパス';
{$IFDEF DEBUG}
database := 'localhost:' + database;
{$ENDIF}
IBDatabase2.DatabaseName := database;
の様にコーディングしています。
ビルド時に、ビルド構成を"Debug"と"Release"とを選択切り替えする様にしています。サーバー接続の切り替えがうまくいっていないのでしょうか?
だとしても、Embedded Serverでサポートされていないのも困ってしまいますが、、、、
よろしくお願いします。
分かりました。
"LoadFromFile"の第2引数を、過去の例から倣って"ftBlob"に変更してみたら、正常に動作しました。
IBQuery2.ParamByName( 'PORTRAIT' ).LoadFromFile( portrait_file, ftBlob );
お騒がせ致しました。
良く理解しないで使うと思わぬ迷宮に入ってしまいますね。
皆様、今回も有益なご教授をありがとうございました。
ツイート | ![]() |