C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[56208] Re:Re:DBExpress에서 BigInt 문제 해결법이..
슬픈사슴 [interest] 2467 읽음    2009-02-19 13:23
답변감사합니다.
아래 답변을 본 후에 다시 몇가지 실험을 해 본 결과, Mysql(Linux 서버 3.22버전)에 Field가 BigInt 타입인 경우 아마도 빌더가 읽어 오면서 대부분 BCD 타입으로 인식을 하고 있는듯합니다.

UID Field가 BigInt 일때, 다음와 같은 소스코드를 확인한 결과,
AnsiString aszSQL = "Select UID From Table Limit 1";
int recCount = this->select(this->pSQLQuery,szSQL);
if(recCount == RECORD_NONE) return LOAD_DATA_NOT_FOUND;
TLargeintField *pUIDField   = dynamic_cast<TLargeintField *>(this->pSQLQuery->FieldByName("UID"));
TFMTBCDField *pFBCDUIDField = dynamic_cast<TFMTBCDField *>(this->pSQLQuery->FieldByName("UID"));
TBCDField *pBCDUIDField     = dynamic_cast<TBCDField *>(this->pSQLQuery->FieldByName("UID"));

이 결과로 DB에 들어있는 UID의 값에 따라 생성되는 구상클래스가 TBCDFiled, 또는 TFMTBCDFiled로 만들어지던군요. 하여 다시 Query를 'Select 4200000000 As UID From Table Limit 1', 과 'Select 42000000000 As UID From Table Limit 1'으로 했을때 TBCDField 로 구상클래스가 만들어지고, 이 경우 값이 4바이트를 넘을 경우는 AsInteger 로는 당연히 정상적인 값을 가져올 수 없구요. AsString으로는 정상적인 값을 추출 가능했습니다.

아래 답변에서 말씀하신 TLargeintField 는 어느 경우에도 만들어 지지 않더라구요.
문제는 제가 쓰고 있는 DB의 실제 값인 2583024897676541956 등은 구상클래스는 TFMTBCDFiled로 만들어지기는 하는데, 이 TFMTBCDFiled 클래스는 GetLargeInt 등의 Method 가 없고 AsInteger,AsString등은 일단 BCDField로 변환하고 값을 추출하는 듯해서 결국은 원하는 결과를 얻지 못했습니다. (나중에야 이 결과를 대충이라도 추측햇지만요)

자료를 좀 더 조사해 보니 BCD Type은 십진수의 각 자리수를 4비트로 표현해서 값을 가지고 있는 아직 잘 알지 못한 타입(이거 보니까 예전에 까마득할때 배운 EBCDIC 코드가 생각났습니다.)인데.... FMTBCD 타입이나, BCD타입이나 자리수에는 크게 영향이 없을 것이라고 판단되었습니다. 위의 테스트 결과 BCD타입도 1000억 이상까지 쓸수 있고 정확한 MAXValue는 아직 테스트 해 보지 못했지만 아마도 구조로 봐서 '0x0F............' 얼마일거라는 막연한 생각이...
즉 BCD타입으로 표현할 수 없는 수라면 결국 FMTBCD타입으로도 표현 할 수 없겟죠.

빌더가 2583024897676541956등의 값을 보면 Field타입을 TFMTBCDFiled class로 구상클래스로 만드는것을 보면 어떤 의미가 있어서 만들기는 하는듯한데 일단은 AsInteger, AsString등의 method는 값을 추출 하기 이전에 일단 BCD타입으로 형 변환후 그 BCD 타입으로 결과를 만들어 추출하므로 2583024897676541956등 값은 '2.650353....... is not valid BCD value'등의 예외를 발생시킵니다. AsVariant 도 도움말을 보아하니 'Represents the value of a binary-coded decimal field as a Variant.'로 역시 BCD형변환이 우선 일어날듯하니 못쓰겟더라구요.

답변하신 내용중에 여담 부분은 우선은 각 Field의 값추출, 쓰기 등의 명확한 동작 확인후 의견을 참고하겟습니다. (라고 쓰고 대부분 '처음 사용한 코드는 그냥 쓴다'라고 읽죠. ^^)

결국은 unsigned형 8bytes의 Full 추출은 아직도 헤메고 있네요.
하지만 답변감사합니다. 덕분에 많은 공부되었습니다.


박지훈.임프 님이 쓰신 글 :
: 그냥 필드 객체가 TField 타입인 그대로 상태에서 AsInteger 등으로 값을 가져오셨나봅니다.
:
: 데이터베이스에서 쿼리를 통해 결과셋을 가져오면, 그때 자동으로 생성되는 필드들은 실제 TField 타입이 아니라, 데이터베이스상의 해당 컬럼에 해당하는 필드 타입으로 돌아옵니다. 이런 모든 필드 타입들이 TField에서 상속된 것이기 때문에 공통적으로 TField 타입으로 액세스가 가능할 뿐이구요. 예를 들어 FieldByName이나 Fields 등은 모든 필드 타입에 대해 다 동작해야 하기 때문에 돌아오는 타입은 항상 TField 타입으로만 돌아옵니다.
:
: 예를 들어 디비상의 실제 컬럼의 타입이 char나 varchar 등이었다면 데이터를 가져왔을 때 데이터셋에 생성되는 필드는 TStringField 타입이고, 컬럼이 4바이트 정수였다면 TIntegerField 타입의 컬럼 객체가 생성됩니다.
:
: 마찬가지로, 해당 필드가 데이터베이스에서 8바이트 unsigned 정수인 경우라면 TLargeIntField 타입의 필드 객체가 생성되었을 겁니다. 따라서, FieldByName이나 Fields로 가져온 필드 객체를 TLargeIntField로 캐스팅한 후 AsLargeInt 속성으로 액세스하면 64비트 정수값인 Int64 타입의 값을 바로 가져올 수 있게 됩니다.
:
: 여담으로...
: 단 하나의 쿼리 컴포넌트로 수많은 SQL문들을 꼭 돌려가며 써야 하는 경우가 아니고, 몇 개 이내의 제한된 SQL 문을 사용하는 경우라면, 여러가지 이유로 각각의 SQL문마다 전용의 쿼리 컴포넌트를 지정해주는 것이 좋은데요. 성능상으로도 더 좋고, 또 이렇게 SQL문을 전용으로 지정해놓은 경우에는 디자인타임에 쿼리 컴포넌트에서 정적으로 필드 객체들을 생성해놓을 수 있습니다. 그러면 코드에서는 해당 필드객체, 즉 정확한 필드 타입으로 이미 폼에서 정의된 객체를 바로 액세스할 수 있게 되므로 캐스팅하고 어쩌고 하면서 복잡한 단계를 거칠 필요없이 단순한 코드로 액세스할 수 있게 됩니다.
:
: 그럼...
:
:
: 슬픈사슴 님이 쓰신 글 :
: : 안녕하세요.
: : 빌더, 오랬만에 잡습니다.
: : 빌더로 MysqlDB를 처리해서 해봐야 할 사항이 있는데 DB Field에 BigInt로 잡혀있는 필드가 Select 시 읽기에서 문제가 좀 있네요.
: :
: : 여기 검색해 보았지만 마땅한 해결책이 보이지 않아 질문드립니다.
: :
: : 우선 CBuilder 6.0 을 쓰고 있습니다.
: :
: : 커넥션은 TSQLConnection, Query는 TSQLQuery를 쓰는데 사용하는 Mysql DB는 3.22(구닥다리지만 워낙에 빨라서..)
: :
: : 문제는 요 DB의 테이블에 BigInt 형이 들어 있구요. 실제 데이터도 8바이트 unsigned정수를 전부 사용합니다. Unique ID가 발급된 필드죠.
: :
: : 4바이트 정수 범위를 넘어가지 않은 숫자면 TSQLQuery에서도 AsInteger, AsString 등으로 정상적인 읽기가 가능한데 실제 DB에 들어있는값은 4바이트 정수 범위를 넘어갑니다.  EX : 2583024897676541956
: :
: : 근데 요넘이 TSQLQuery에서 읽어 들일려면 예외가 발생하네요. "2.650353....... is not valid BCD value" 인터넷이나 이 사이트를 뒤져보면 AsFMTBCD 쓰라고 하는데.. 찻은건 저장할때 쓰는 방법뿐이였고 읽어올때도 쓰는 방법은 찻지를 못했습니다.
: :
: : 머 얼마전부터 UID발급은 4바이트 정수에 한계를 느껴서 아예 신경안쓰고 잊어버리게 8Byte 정수를 쓴게 빌더가 발목을 잡네요.
: :
: : 현재는 변칙적인 방법으로 해결해서 쓰고 있습니다만 해결하신 분 있으시면 정보 공유 부탁드립니다.
: : 제가 변칙적으로 쓰는 방법은 Select 할때 BigInt 쓰는 부분은 CONCAT으로 필드형 자체를 문자열형으로 나오게 해서 Buider에서 문자열로 취급하게 한 후 AsString으로 읽어들입니다. 일단 문자열로 만든뒤로는 뭔짓이든 할 수 있겟죠.
: : 하지만 이방법은 Select * 같이 간단한 Query는 만들 수가 없어 소스가 많이 귀찮아집니다.

+ -

관련 글 리스트
56196 DBExpress에서 BigInt 문제 해결법이.. 슬픈사슴 1245 2009/02/18
56202     Re:DBExpress에서 BigInt 문제 해결법이.. 박지훈.임프 1142 2009/02/19
56208         Re:Re:DBExpress에서 BigInt 문제 해결법이.. 슬픈사슴 2467 2009/02/19
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.