본문 바로가기

C / C++ / Win32 / MFC

ODBC Error - State:01004 문자열 데이터의 오른쪽이 잘렸습니다. 무시하기

본 포스트는 2006/8/3 작성되었습니다.

작년 10월부터 4개월여간 S은행 기업용 인터넷뱅킹 시스템에 사용되어질

그리드 컴포넌트를 ActiveX로 개발한 적이 있습니다.

그리드의 기본적인 기능은 물론이고

XML / CVS / 엑셀 파일 지원

다중 선택을 이용한 copy / paste

셀편집 컨트롤 지원(Edit / Combobox / Radio / Check / 달력)

사용자 서식 디자인 적용 등등등.....

초보적인 엑셀의 기능이 모두 구현된

300 여개의 메소드를 제공하는 놈이었습니다.

 

개발이 끝나고 잔금까지 다 받고 6개월이 지난 지금까지 별 문제 없이 그쪽 개발자들이 내가 만든 컴포넌트를 이용해 시스템 개발을 해오고 있었습니다. 한 달에 한 두 건 정도 몇몇 사소한 버그를 처리해주는 것 말고는 신경 쓸 일이 없었습니다. (스크롤바 위치가 이상해요. 데이터 입출력 할 때 Trim을 해주세요, 특정 유니코드로 인코딩이 가능하도록 해주세요 등등)

 

그러던 중

휴가를 끝내고 첫 출근을 한 월요일.

일이 터지고 말았습니다.

시스템 개발을 맡은 회사의 개발팀장의 다급한 전화를 받은 것이죠

 

그리드의 부가 기능 중에

사용자에 의해 미리 설정된 DSN 정보를 가지고 DB의 종류에 관계없이

해당 쿼리를 실행시켜 그 데이터를 그리드로 가져오는 기능이 있었습니다.

테스트는 MS-SQL / Oracle / DB2 / Infomix 이렇게 테스트를 거쳤습니다.

 

그런데 시스템 개발을 맡은 팀원 중 한 사람이

Access 를 테스트를 해보았는데 쿼리 실행이 안된다는 것이었습니다.

8월 4일까지가 프로젝트 마감이라고 하면서 다급하게 처리해달라고 하더군요

어쩌겠습니까?

검수가 6개월이 지나긴 했지만 우리가 저지른 일은 끝까지 우리가 책임져야 한다는 어찌보면 개발자에게 너무나 큰 십자가가 될 수 있는 우리 팀의 신념 때문에 처리해 주어야 했습니다.

 

쿼리 오동작의 원인은....

이 개발자가 오라클의 데이터를 Access 로 강제 변환을 했는데  무슨 이유인지는 모르겠지만

모든 필드는 문자열로 변환되고 필드 사이즈 보다 큰 사이즈로 데이터의 끝부분이 공백으로 채워져 있었습니다

예를 들면 필드 사이즈가 30 인 필드에서 "결재A"라는 데이터가 저장되어 있다면 Access 로 변환되는 과정에서 "결재A                (공백 26개)      " 가 저장되어 있다는것이었습니다.

공백이 25개도 아니고 왜 26개가 되었을 까요?  01004 에러가 난 것이 바로 이 이유에서였더군요

 

이틀을 고심꿑에 해결방법을 찾지 못하다가 그냥 꽁수를 써버리고 말았습니다.

그리드에서는 데이터베이스에 값을 가지고 오기 위해

쿼리 결과를 CRecordset을 상속받아 CxDBARecordset 이라는 클래스를 만들어서 처리하는데 01004 에러로 인한 exceoption 이 void CRecordset::CheckRowsetError(RETCODE nRetCode) 함수에서 발생되더군요

그래서 그 놈을 virtual 로 CxDBARecordset 안에 선언하고 아래와 같이 코드를 변경해 버렸더니 잘 작동이 되더군요

 

void CRecordset::CheckRowsetError(RETCODE nRetCode)
{
 if (nRetCode == SQL_SUCCESS_WITH_INFO)
 {
  CDBException e(nRetCode);
  // Build the error string but don't send nuisance output to TRACE window
  e.BuildErrorString(m_pDatabase, m_hstmt, FALSE);

  if (e.m_strStateNativeOrigin.Find(_afxDataTruncated) >= 0)
  {
   // Ignore data truncated warning if binding long binary columns
   // (may mask non-long binary truncation warnings or other warnings)
   if (!((m_pDatabase->m_dwUpdateOptions & AFX_SQL_SETPOSUPDATES) &&
    m_bLongBinaryColumns))
   {
    NO_CPP_EXCEPTION(e.Empty());
    TRACE(traceDatabase, 0, _T("Error: field data truncated during data fetch.\n"));
    ThrowDBException(AFX_SQL_ERROR_DATA_TRUNCATED);
   }
  }
  else if (e.m_strStateNativeOrigin.Find(_afxRowFetch) >= 0)
  {
#ifdef _DEBUG
   TRACE(traceDatabase, 0, _T("Error: fetching row from server.\n"));
   e.TraceErrorMessage(e.m_strError);
   e.TraceErrorMessage(e.m_strStateNativeOrigin);
#endif
   NO_CPP_EXCEPTION(e.Empty());
   ThrowDBException(AFX_SQL_ERROR_ROW_FETCH);
  }
#ifdef _DEBUG
  else
  {
   // Not a truncation or row fetch warning so send debug output
   TRACE(traceDatabase, 0, _T("Warning: ODBC Success With Info,\n"));
   e.TraceErrorMessage(e.m_strError);
   e.TraceErrorMessage(e.m_strStateNativeOrigin);
  }
#endif // _DEBUG
 }
 else if (!Check(nRetCode))
  ThrowDBException(nRetCode);
}

 

위에놈을 아래놈으로 virtual 로 재정의...

중간에 Exception 일으키는 놈을 싹 지워버렸습니다.

 void CxDBARecordset::CheckRowsetError(RETCODE nRetCode)
{
 if (nRetCode == SQL_SUCCESS_WITH_INFO)
 {
 }
 else if (!Check(nRetCode))
  ThrowDBException(nRetCode);
}


01004 에러가 얼마나 심각한진 모르겠지만

단순한 Select 처리는 굳이 릴리즈에서  Exceprion으로 처리하지 않아도 될거 같은데...

여러분의 생각은 어떤지요?