SQLサーバ処理でエラー時の処理について – プログラミング – Home

SQLサーバ処理でエラー時の処理につい...
 
通知
すべてクリア

[解決済] SQLサーバ処理でエラー時の処理について


田中さん
 田中さん
(@田中さん)
ゲスト
結合: 19年前
投稿: 49
Topic starter  

開発環境VisualC++、SDK開発 Windows2003Server SQLServer2000

SQLサーバーに値を入力するプログラムを作っています。
そこで質問なのですが、Try処理でデータを入力しようとして、制約違反でエラーとなっ
た場合の処理について質問です。

データを登録するコードは以下のようにしています。
int SqlCds::Test(){
HRESULT hr = S_OK;

//ADOオブジェクト
_ConnectionPtr pConnection = NULL; //コネクション作成
_CommandPtr pCmdChange = NULL; //コマンド作成

try
{
//DB接続
_bstr_t strCnn(STR_CNN);//接続文字
TESTHR(pConnection.CreateInstance(__uuidof(Connection)));//インスタンス作成
pConnection->Open (strCnn, ", ", adConnectUnspecified);//コネクションOPEN
pConnection->Errors->Clear(); //DB接続のエラーをクリアする

//コマンドの実行
_bstr_t strSQLChange(INSERT INTO TEST (日付) VALUES(20060723));//コマンド文字
TESTHR(pCmdChange.CreateInstance(__uuidof(Command))); //コマンド作成
pCmdChange->ActiveConnection = pConnection; //コマンド
pCmdChange->CommandText = strSQLChange; //コマンドテキストを関連付け

pCmdChange->Execute(NULL,NULL,adExecuteNoRecords);//返事を返さなくても良い処理

//クローズ
pCmdChange->Release();
pConnection->Close();
}
catch (_com_error &e)
{
//エラー処理
PrintProviderError(pConnection);
PrintComError(e);
}
return TRUE;
}

この処理でデータは正常に登録できます。ただ、わざと制約違反のデータを登録した場合
にエラーが発生し、エラーメッセージを吐き出させるまではOKですが、その後、
ハンドルされていない例外が発生し、止まります。
エラーがおきる場所はcomutil.hの以下の場所です。

inline unsigned long _bstr_t::Data_t::Release() throw()
{
//ここの処理で止まる
if (!InterlockedDecrement(reinterpret_cast<long*>(&m_RefCount))) {
delete this;
return 0;
}
return m_RefCount;
}

エラー処理は以下のコードです。

///////////////////////////////////////////////
// ProviderError を表示する関数
///////////////////////////////////////////////
void SqlCds::PrintProviderError(_ConnectionPtr pConnection)
{

char emsg[256]; //エラー文字
ErrorPtr pErr = NULL;

//初期化
memset(&emsg,0,sizeof(emsg));

if( (pConnection->Errors->Count) > 0)
{
long nCount = pConnection->Errors->Count;
// Collection ranges from 0 to nCount -1.
for(long i = 0; i < nCount; i++)
{
pErr = pConnection->Errors->GetItem(i);
wsprintf(emsg,<ProviderError> \n number[%x]:%s, pErr->Number,pErr-
>Description);
OutputDebugStr(emsg);
//MessageBox(NULL,emsg,SQL ProviderError,MB_OK);
}
}
}

//////////////////////////////////////
// ComError を表示する関数
//////////////////////////////////////

void SqlCds::PrintComError(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());

//エラーメッセージの作成
char emsg[256];
memset(&emsg,0,sizeof(emsg));

wsprintf(emsg,<ComError>:\n\t Code=%081x\n\t Code meaning=%s\n\t Source=%
s\n\t Description=%s\n,e.Error(),(char*) e.ErrorMessage(),(char*) e.Source(),
(char*) e.Description());
//MessageBox(NULL,emsg,SQLエラー,MB_OK);
OutputDebugStr(emsg);
}

MSDNを参考にコードを作ったつもりなのですが、エラー処理でマズイ所どのあたりでしょ
うか?


引用未解決
トピックタグ
…
 …
(@…)
ゲスト
結合: 22年前
投稿: 113
 

本題とは関係ないけれど

>_bstr_t bstrSource(e.Source());
>_bstr_t bstrDescription(e.Description());
使ってないような…

><ComError>:\n\t Code=%081x\n\t Code meaning=%s\n\t Source=%s\n\t 
Description=%s\n
これ固定文字列部分だけでも144バイトあるけどバッファ足りる?


返信引用
…
 …
(@…)
ゲスト
結合: 22年前
投稿: 113
 

>><ComError>:\n\t Code=%081x\n\t Code meaning=%s\n\t Source=%s\n\t 
>Description=%s\n
>これ固定文字列部分だけでも144バイトあるけどバッファ足りる?
Code=%081x

Code=%08x
のタイプミス?


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 23年前
投稿: 1235
 

> char emsg[256];
サイズが小さいですね。
ODBC-SDKで言うサーバからのエラーメッセージを保存するなら、
500以上はあってもいいはず。
文字列(ソース上だと、「e.ErrorMessage()」かな?)だけで256バイト近くいく可能性
があります。(英文だと分らない)
MFCの関数だと、エラー処理は「Try-catch」になるんですね。
エラー処理には、入るみたいなんで、「Try-catch」はうまくいっているのですね。
使ったことがないんで分りませんが、「_com_error」の使い方はあっていますか?


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 23年前
投稿: 1235
 

「OutputDebugStr」→「OutputDebugString」ですか?


返信引用
田中さん
 田中さん
(@田中さん)
ゲスト
結合: 19年前
投稿: 49
Topic starter  

ご返事ありがとうございます。
結論はエラーメッセージのBUFF不足でした。BUFFを500にすればエラーは出さないように
なりました。

>>_bstr_t bstrSource(e.Source());
>>_bstr_t bstrDescription(e.Description());
>使ってないような…
確かにコメントアウトしても問題なく動作しました。必要なかったのかな・・・?

>Code=%081xはCode=%08xのタイプミス?
その通りでした。修正しました。

>「OutputDebugStr」→「OutputDebugString」ですか?
「OutputDebugString」です。
OutputDebugStrはどこかでマクロが定義されているようなので、これでも動作するようで
す。

ただ、もうひとつ、上記のProviderError を表示する関数でエラーメッセージが文字化け
します。

関数は以下のように修正しました。

///////////////////////////////////////////////
// ProviderError を表示する関数
///////////////////////////////////////////////
void SqlCds::PrintProviderError(_ConnectionPtr pConnection)
{
char emsg[4000]; //エラー文字。念のため4000に設定
ErrorPtr pErr = NULL;

//初期化
memset(&emsg,0,sizeof(emsg));

if( (pConnection->Errors->Count) > 0)
{
long nCount = pConnection->Errors->Count;
for(long i = 0; i < nCount; i++)
{
pErr = pConnection->Errors->GetItem(i);
wsprintf(emsg,<ProviderError> \n number[%x]:%s\r\n,
  pErr->Number,pErr->Description);
OutputDebugStr(emsg);
//MessageBox(NULL,emsg,SQL ProviderError,MB_OK);
}
}
}

//関数はここまで。

出力されたエラーメッセージは以下のようになります
<ProviderError>
number[80040e2f]:フソ
<ProviderError>
number[80040e2f]:ト

ちなみにComErrorを表示する関数は問題なく以下のメッセージを吐き出します。
<ComError>:
Code=80040e2f
Code meaning=IDispatch error #3119
Source=Microsoft OLE DB Provider for SQL Server
Description=PRIMARY KEY 違反、制約 'PK_TEST': オブジェクト 'TEST' に
は重複したキーは挿入できません。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

もしかして、pErr->Description の戻り値が _bstr_t ではないでしょうか?
その場合、wsprintf関数に渡すときにキャストをする(operator const char*を呼ぶ)必
要がありそう。

MSDNのサンプルでは LPCTSTR でキャストしています。
http://msdn.microsoft.com/library/ja/default.asp?
url=/library/ja/jpado260/htm/mdproconnectionstringxvc.asp
> printf(Error number: %x\t%s\n, pErr->Number,
> (LPCSTR)pErr->Description);


返信引用
田中さん
 田中さん
(@田中さん)
ゲスト
結合: 19年前
投稿: 49
Topic starter  

Blueさんありがとうございました。
まさしく原因はそれでした。

wsprintf(emsg,<ProviderError> \n number[%x]:%s\r\n,
pErr->Number,(LPCSTR)pErr->Description);

とする事で解決しました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました