ADOでSQL文をExecuteするとエラー

[戻る]
またんご 2005/04/07(木) 18:42:03
はじめまして、またんごです。
当方VC++知識は基礎レベルでADOは今回が初めての開発です。
他人(もう会社に居ない人)のプログラムを修正中です。
どなたかお力を貸してください!

現象:
VC++から接続先がDB2サーバーで、問題なく接続しています。
通常のSQL文をExecuteする場合も特に問題なく動作しています。
なのに、大きな項目(990byte)を持つテーブルに940byteの値を
セットしようとすると下記のエラーが発生して終了します。

 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 [DB2] SQL0102N  "***" で始まるストリング定数が長すぎます。  
 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

その項目に例えば160byte位の値をセットする場合は問題なく動きます。
また、Executeしている長いSQL文をAccessで実行すると問題なく
Insertできています。

これってどこに問題があるのでしょうか?
ADO内部でのコマンド解釈時に項目のバイト数の制限があるのでしょうか?
何か記述がぬけているのでしょうか?

int DBInsertSQL::insert(CStringArray & Record)
{

    ADODB::_CommandPtr adoCommand;
    adoCommand.CreateInstance(__uuidof(ADODB::Command));

    CString SQL = m_SQL_INPUT_STATEMENT;    //SQL文--1109byte

    //コンソールにSQL文を表示
    cerr << _bstr_t(SQL);    //coutだと表示が短く切られるのでcerr(バッファ
リングなし)

    m_Con->Execute(_bstr_t(SQL),NULL,-1);

    return 1;
}


ちなみにSQL文はSPではなく直書きSQL文で、
msado15.dllをインポートしてADOを使用しています。
よろしくお願いします。

wood 2005/04/08(金) 05:03:11
異常終了する「m_SQL_INPUT_STATEMENT」の中身提示してみてはいかがでしょうか
また「m_Con」はどんなクラスがベースになってるか説明したほうっが良いと思います
SQLで巨大定数はあまり使わず、ホスト変数に代入するのが良いのではないでしょう
か
ホスト変数を使用できないのであれば、理由を説明したほうが、レス付くんじゃないで
すか

ぼくぼく詐欺 2005/04/08(金) 10:10:01
http://www.db2.jp/siryo/db2online/db2m0/frame3.htm#sql0100


これは、データ変換が行われて、その結果のストリングが長過ぎる状態に
なる可能性があります。アプリケーションと、異なったコード・ページの
もとで実行されるデータベースとの結合では、ストリング定数はアプリケ
ーション・コード・ページからデータベース・コード・ページに変換され
ます。特定の状況 (データベースが EUC コード・ページで作成された時
など) では、グラフィック・ストリング定数は、データベース・コード・
ページから UCS-2 (UNICODE) エンコードにさらに変換される場合があり
ます。これは、入力ストリングより長い結果のストリングをもつ可能性が
あることを意味します。 

これではないでしょうか?

DB2使ったことないからわかりませんが、990byteのフィールドを
1500byteにしてみたら、940byteは格納できるんですか?

またんご 2005/04/08(金) 10:46:14
woodさんレスありがとうございます。

> 異常終了する「m_SQL_INPUT_STATEMENT」の中身提示してみては

m_SQL_INPUT_STATEMENTはInsert文です。
990byte項目に940byteの文字列をセットしたものがAccessに記述して実行した場合
正常終了しており、データは正しくInsertできましたのでSQL文には問題はないと
思うのです。

> 「m_Con」はどんなクラスがベースになってるか説明したほうっが良いと思います

m_Conは、msado15.dllをインポートしており、自動的に実行ディレクトリに
作成されるADOのラップクラス【msado15.tlh】をインクルードしていますが、
この中にある
  _COM_SMARTPTR_TYPEDEF(_Connection, __uuidof(_Connection));
という宣言を利用してコネクションポインタ(m_Con)としています。
また、Execute関数はmsado15.thiに定義されているConnection15::Executeです。
990byte項目に160byteの文字列をセットした場合はうまく動いているので
これ(コネクションクラス)も特に問題ないのではないかと思います。


> SQLで巨大定数はあまり使わず、ホスト変数に代入するのが良いのではないでしょう
か

ぐぐったのですが【ホスト変数】というのがよく分かりませんでした。
すみません、もうすこしご説明いただけないでしょうか。。
現状は先述の関数を共通関数としていたためこの手順でのみ考えていましたが、
もし他のでうまくいくならそれでも構わないと考えています。
あと「何か記述がぬけているのでしょうか?」と訊いたのは、ADOになれていないため
項目桁数の設定コマンドがあるのを知らないのかもと思ったからです。

wood 2005/04/08(金) 15:52:25
【ホスト変数】
ADOにはこんな考えないのかも?
言葉を提示した手前の例ですが

----------- ホスト変数 宣言 -------- 
EXEC SQL
 int  Namber;
 char Title[512];
END-EXEC

----------- 実行 部分 ------------
Namber = 10;
sprintf(Title,"title"); /*領域は最大512だけど実際5バイトの定数が
             合致したものを検索する  */


EXEC SQL
   SELECT  AAA,BBB,CCC
     INTO  ADD,BDD,CDD
     FROM  TABLE
    WHERE  番号 = :Namber
      AND  表題 = :Title
END-EXEC
------------------------------------
うろ覚えですがこんな記述の「:Namber」と「:Title」のことです
OS:AIX C言語 DB2
で仕事したときはこんなことをした覚えがあります
ADOではありませんでしたけど

つまり変数を使ったSQL文であれば一定の長さの文字列文であるため
安定動作してくれるのではないかと思いました

この例を定数の文で書くと

EXEC SQL
   SELECT  AAA,BBB,CCC
     INTO  ADD,BDD,CDD
     FROM  TABLE
    WHERE  番号 = 10
      AND  表題 = "title"
END-EXEC

だったり

EXEC SQL
   SELECT  AAA,BBB,CCC
     INTO  ADD,BDD,CDD
     FROM  TABLE
    WHERE  番号 = 10
      AND  表題 = "title1234567890---A"
END-EXEC

だったりして長さがバラバラでSQLエンジンに渡される文字列が
エンジンの性能上で切り落とされてしまう可能性があります

EXEC SQL
   SELECT  AAA,BBB,CCC
     INTO  ADD,BDD,CDD
     FROM  TABLE
    WHERE  番号 = 10
      AND  表題 = "title

これしか
エンジン側で受け取っていない、ため文が中途半端になり
エラー発生なんて事になると思いました

yank 2005/04/09(土) 18:38:05
Execute で全て対応しようと思わずに
_RecordsetPtr 開いて AddNew メソッド を使用するようにしたらいいのでは

またんご 2005/04/28(木) 19:33:51
ご返答くださった皆様ありがとうございました。
途中、別の仕事が入ったりしてなかなか進まなかったのですが
ようやく解決しましたので報告いたします。

まずぼくぼく詐欺さんが教えてくださったページですが、
最初に確認ずみのページでした。
ただ、私の現象ではVBで同じプログラムを作った時にうまくいき
VC++ではうまくいかないということが後で分かったので
これには該当しないと思っています。両者とも前述のDLLを使用しています。
(VBでは Microsoft ActiveX Data Objects 2.5 Libraryを参照)


次にwoodさんの埋め込みSQL文ですが、
調べた感じですと、nmake.exe をつかったりして、
コンパイルを手動で行わなくてはいけないようですね。
これはメンテを考えると業務上無理という結論になりました。
ただSQL文に変数で値を渡すような感じで
作れるかなと思い、結果うまくできました。


yankさんの方法はSelectだけじゃなくInsert文でも可能なのでしょうか?
私の力量・時間不足で試しませんでしたが。

ご報告遅れまして申し訳ありませんでした。
お世話になりました。


################################
下にうまく言ったやり方を書いておきます。稚拙でしたらすみません。
※抜粋のためこのままではうごきませんが何かの参考になれば・・・
################################

  ADODB::_ConnectionPtr  m_Con = m_DB->getCONNECTION();
  ADODB::_CommandPtr adoCmd;
  adoCmd.CreateInstance(__uuidof(ADODB::Command));
  ADODB::_ParameterPtr pParam = NULL;
// CString SQL; 
// ↑SQLに「insert into A values (aa,bb,cc,dd,?,ee)」をセット済み
// CString Param;
// ↑Paramに?部分の値(990byte)をセット済み

  try{
    adoCmd->PutActiveConnection(_variant_t((IDispatch*)m_Con));
    adoCmd->CommandText = _bstr_t(SQL); // 取得したSQL文をセットする

    pParam = adoCmd->CreateParameter("", ADODB::adBSTR,  
            ADODB::adParamInput, strlen(Param), 
            (_variant_t)(Param) );
    adoCmd->Parameters->Append(pParam);

    //SQL文実行
    adoCmd->Execute(NULL, NULL, ADODB::adCmdText);
    adoCmd->Parameters->Release();
  }
  catch(_com_error &e){
    // データ操作失敗
    AfxMessageBox(e.Description());
  }

################################

またんご 2005/04/28(木) 19:34:19
[[解決]]
す、すみません解決チェックわすれました。。

古いスレッドには追加発言できません。