본 장에서는 ODBC API들을 사용하는 방법에 대해서 배우게 된다.
프로그램에서 직접 ODBC 드라이버에게 명령을 내리진 못한다. 그래서 ODBC매니져는
프로그램에서 사용할 수 있는 API들을 제공한다. 만약 프로그램에서 ODBC를 사용하기
위해서는 프로그램 선두부분에 odbc32.inc 파일과 odbc32.lib파일을 추가 해 주면된다.
당연한 얘기지만, windows.inc 파일도 포함해주어야 할것이다. (설명생략)
데이터 소스란 어떠한 컴퓨터에 어떤 데이터베이스 프로그램의 어떤 테이블의
어떤내용을 의미함을 알아두고, 이러한 데이터소스에 연결하는데는 다음과 같은
순서를 따르게 된다.
- 환경핸들 생성
ODBC세션마다 설정해주어야 한다.핸들이 생성되면, 환경변수를 원하는대로
설정할 수있게된다. DB작업을 위해서 작업장을 마련한다고 생각하면 된다. - ODBC버전 설정
ODBC는 2.x / 3.x의 버전이 존재한다. 물론 버전별로 명령이 추가되거나 제거
되어있기때문에, 버전을 정확히 명시해야한다. 이부분은 사용하면서 설명한다. - 연결핸들 생성
상기의 정보를 기반으로 연결용 핸들을 생성한다. 어떤 데이터베이스와 어떤
드라이버를 사용할 지를 아직 정하지 않았다. 이런정보는 나중에 채워넣는다.
단지, 빈상태의 연결용 핸들을 생성하는 것이다. - 연결
연결된 후에는 ODBC의 여러가지 함수를 호출 할 수 있게 된다.
정상적으로 연결한 후 원하는 작업을 마쳤다면 다음과 같은 작업을 수행해야한다.
- 데이터 소스 연결해제
- 연결핸들 해제
- 환경핸들 해제 ( 더이상 사용하지 않을경우만 해제)
ODBC의 버전이 3.x이전에는 , 환경/연결/명령의 핸들 할당용 함수가 따로 존재했었다.
(SQLAllocEnv, SQLAllocConnect, SQLAllocStmt). 그러나 ODBC 3.x버전에서는 한개의
함수를 사용해서 처리할 수 있게 되었다. SQLAllocHandle 함수이다. 레퍼런스에는 다음
과같이 선언되어 있다.(C형태로 되어있음은 예상했을 것이다..)
SQLRETURN SQLAllocHandle( SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandlePtr );
DevX의 어셈블리형태로 변환해보자. 어려운 일이 아니지않는가. 포인터와 핸들은
어셈블리에서는 그냥 Define Doble Word 일뿐이다. 그것에 의미를 두는것은 C와 같은
고급언어의 법칙일 뿐이다.
SQLAllocHandle proto HandleType:DWORD,
InputHandle:DWORD,
OutputHandlePtr:DWORD
SQLRETURN은 SQLSMALLINT 타입으로 선언 되어있고, SQLSMALLINT 타입은
short integer, 즉, 워드크기(16 bits)이다. 그래서 함수의 반환값은 EAX가 아닌 AX에
저장됨을 유의하기 바란다.아주 중요한 것이다. Win32환경에서는 스택이
32비트로 운영된다. 만약 인수가 워드크기로 선언되어 있다면, 반드시 32비트로
크기를 확장해 주어야 한다는 의미이다. odbc32.lib 임포트 라이브러리를 살펴
보면 SQLAllocHandle 은 _SQLAllocHandle@12.로 선언되어있다. 이전장에서 설명
했듯이, 인수의 크기가 12바이트라는 의미다.
SQLAllocHandle 에서는 HandleType 의 하위워드만 사용하고 상위워드는 무시해
버린다.이런점을 염두해 두고 C의 프로토타입을 어셈블리로 조심히 변환하면 된다.
이것은, OS가 C를 기본으로해서 만들어졌기 때문이다. 어셈블리로 못할것은 없다!
- HandleType 은 생성을 위해 선언된 상수이다. 가능한 상수값은 다음과 같다
SQL_HANDLE_ENV | 환경핸들 |
SQL_HANDLE_DBC | 연결핸들 |
SQL_HANDLE_STMT | 명령핸들 |
SQL_HANDLE_DESC | 설명핸들 |
설명핸들은 SQL에서 매개변수를 설명하는 메타데이터이다.또는 결과셋
의 컬럼을 의미하기도 한다. 프로그램과 드라이버에 사용하는 용도가
달라지며, 일반적으로는 자주 쓰이지 않는다.
- InputHandle입력핸들은 "context"의 부모핸들을 의미한다. 예를 들어, 연결핸들을
생성했다면, 환경핸들을 필요로한다. 즉 연결핸들의 부모는 환경핸들이 되는
것이다. 만약 환경핸들이라면 부모핸들이 없으므로, SQL_HANDLE_NULL 로 지정
되어야만 한다.명령핸들과 설명핸들일 경우에 부모핸들은 연결핸들이 될것이다.- OutputHandlePtr
출력핸들은 성공적으로 수행됬을경우 생성되는 핸들이다. - OutputHandlePtr
가능한 반환값으로는 다음과 같은 것이 있다.(SQLAllocHandle)
SQL_SUCCESS | 성공적으로 수행되었을 경우 |
SQL_SUCCESS_WITH_INFO | 성공적으로 수행되었을 경우, 그러나 경고가 발생 |
SQL_ERROR | 수행 실패 |
SQL_INVALID_HANDLE | 부적절한 핸들 |
함수가 성공적으로 수행되거나 실패를 할경우에,SQLGetDiagRec / SQLGetDiagField.
함수를 수행해서 자세한 정보를 알 수 있으며, 일반적으로는 GetLastError 함수를
수행해서 알아낸다. 이것은 Win32 API함수이다..
코드샘플
.data?
hEnv dd ?
.code
invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
::: ODBC 버전 선택 :::
환경핸들이 생성된 후에는, 환경변수를 설정해야 한다. 이중에서도 ODBC의 버전설정
을 해주어야 원활히 수행될 것이다. SQL_ATTR_ODBC_VERSION,값을 변경해주어야한다. 이러한,
속성들은 단지 변수일 뿐이다. 환경변수를 설정하는 함수는 SQLSetEnvAttr. 를 호출해서 변경할 수 있다.
3.x버전 이전에는 SQLSetConnectAttr / SQLSetStmtAttr / SQLSetEnvAttr 함수도 같은 의미이다.
버전에 따라 사용하기 바란다.
SQLSetEnvAttr proto EnvironmentHandle:DWORD,
Attribute:DWORD,
ValuePtr:DWORD, StringLength:DWORD
- EnvironmentHandle.
자기자신을 의미한다.(이미 환경핸들이므로..) 환경변수를 수정할 환경핸들을
지정하는 것이다. - Attribute.
변경하고 싶은 속성을 명시한다. 자세한것은 MSDN을 참고하고 현재 우리는
SQL_ATTR_ODBC_VERSION을 변경하고 싶은것이다 - ValuePtr.
이것은 변경할려는 속성값에 따라 달라진다. 속성이 32비트값이라면,이값은
변경할 값이 된다. 만약 변경할려는 값이 문자열이거나 이진버퍼값이라면
이값은 문자열의 주소와 버퍼의 주소값을 가지게 될 것이다.
여기에서는 SQL_ATTR_ODBC_VERSION을 의미하므로, 2가지 값을 설정할 수
있다. SQL_OV_ODBC3 / SQL_OV_ODBC2값이 그것이다. 각각의 의미는 말그대로
ODBC버전 2.x / 3.x을 설정하는 것이다. - StringLength.
ValuePtr가 가르키는 값에 대한 크기를 지정한다. 값이 만약 문자열이거나
이진버퍼라면 이값은 반드시 지정되어야만 한다.만약 더블워드크기값을
설정하고 싶다면 이값은 무시된다.
SQL_ATTR_ODBC_VERSION 속성은 더블워드 크기이다.그래서 NULL값을
설정해서 이값을 무시하게 되는 것이다. 문자열과 버퍼라면 sizeof 연산자로
그크기를 지정해야 할 것이다.
코드샘플
.data?
hEnv dd ?
.code
invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke SQLSetEnvAttr, hEnv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, NULL
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
::: 연결핸들 생성:::
환경핸들을 생성할때와 유사한 방법으로 연결핸들을 생성한다.
SQLAllocHandle 프로시져를 호출하되, 인자만 연결용으로 설정해서 호출하면 된다.
코드샘플
.data?
hEnv dd ?
hConn dd ?
.code
invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke SQLSetEnvAttr, hEnv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, NULL
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
invoke SQLAllocHandle, SQL_HANDLE_DBC, hEnv, addr hConn
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
::: 연결 :::
이제는 ODBC드라이버를 사용해서 원하는 데이터소스에 연결할 준비가 되었다.
실제연결에 필요한 함수는 대략 3가지가 존재한다. 필요에 따라 선택하기 바란다.
ODBC매니져함수는 3단계로 이루어져있다. 코어레벨과 레벨 1/2 로 되어있는데,
자세한것은 몰라도 되며, MSDN을 참고하길 바란다. 단지 어디에 속하는지만 알면된다.
SQLConnect | Core | 가장 간단히 연결하는 명령이다. 이것은 DSN(데이터소스이름) 명만 지정하면 된다. (모든정보는 DSN에 설정되어있으므로) 추가로, 사용자명과 비밀번호를 설정 할 수있다. 그러나, 이 프로시져는 매개변수가 틀렸을 경우 대화상자가 나타나서 수정할 수 있는 기회를 제공하지 않는다. 이것은, 데이터원본 에서 원하는 DSN을 설정하였을 경우에 사용하면 편리한 프로시져이다. 확장문자열등은 제공하지 못하며, 그래서 가장 간단한 프로시져인 것이다. 미리 제어판의 데이터원본에 설정이 되어있어야만 한다. |
SQLDriverConnect | Core | SQLConnect프로시져보다 조금더 많은 기능을 제공하는 프로시져이다.DSN이 지정되어 있지 않아도 데이터소스에 연결할 수 있다. 만약 원하는 정보가 누락되었다면, 대화상자가 나타나고 사용자에게 정확한 데이터소스를 지정할 기회도 제공한다. 즉, 데이터베이스 이름과 드라이버등을 잘못 지정해서, 연결이 되지 않으면 연결 대화상자가 나타나서 교정할 기회를 준다는 의미이다. 또한 DSN이 설정되어 있지 않아도 사용하므로 배포할 때도 편리하다. |
SQLBrowseConnect | Level 1 | 이 프로시져는 실행시에 모든것을 설정할 기회를 제공해주는 프로시져이다. 즉 SQLDriverConnect 프로시져에서 한단계 더 진보(?)한 프로시져이다. 데이터소스가 자주 바뀐다면 변경한 데이터소스를 대화상자를 통해서 실행시에 변경할 기회를 제공해주는 프로시져라고 생각하면 된다. |
가장 먼저 SQLConnect 프로시져를 설명할 것이다. SQLConnect 프로시져는 상기에서
설명했듯이 DSN을 요구한다. DSN(Data Source Name)은 제어판의 데이터원본에서 설정
하는 것이다. 파일DSN / 시스템DSN / 사용자DSN등이 존재한다. 사용자DSN은 다중사용자 시스템인 윈도우환경에서 사용자별로 접근을 허가하는 DSN이고, 시스템DSN은 모든사용자에게 허용하는 DSN이며, 파일 DSN은 말그대로 이러한 정보가 저장된 DSN파일을 지정하는 것이다. 각각은 레지스트리에 각각 저장되게 되며, 제어판의 데이터원본에서
표시되게 되는 것이다. 이러한 DSN에는 데이터소스에 연결하는 방법이 설정되어있다. ODBC드라이버와 어떠한 데이터베이스를 연결할 지 등에 대한 정보가 기록된 것이다. 원하는 데이터소스에 접근하는 DSN을 생성하였다면 SQLConnect프로시져로 연결할 수 있는 것이다.
SQLConnect proto ConnectionHandle:DWORD
pDSN:DWORD,
DSNLength:DWORD,
pUserName:DWORD,
NameLength:DWORD,
pPassword:DWORD,
PasswordLength:DWORD
- ConnectionHandle. 연결핸들을 지정한다.
- pDSN. DSN문자열의 포인터.
- DSNLength. DSN 문자열의 길이
- pUserName. 사용자이름의 포인터
- NameLength. 사용자이름의 크기
- pPassword. 비밀번호가 저장된 곳의 포인터
- PasswordLength. 비밀번호의 크기
SQLConnect 프로시져는 최소한 연결핸들을 필요로 한다.DSN에 따라서는 사용자이름과
비밀번호를 요구하지 않는 경우도 있기 때문이다. 반환값으로는 구별가능한 SQLAllocHandle값을
반환해 준다.
예를 들어서 DSN이름이 "Sales" 인 데이터소스에 연결하기 위한 예제는 다음과 같다
.data
DSN db "Sales",0
.code
......
invoke SQLConnect, hConn, addr DSN, sizeof DSN,0,0,0,0
SQLConnect 프로시져의 단점은 말했다시피 사용하기 전에 미리 DSN을 설정해 두어야한다는 것이다.
SQLDriverConnect 프로시져는 이러한 단점을 보완해준다.
SQLDriverConnect proto ConnectionHandle:DWORD,
hWnd:DWORD,
pInConnectString:DWORD,
InStringLength:DWORD,
pOutConnectString:DWORD,
OutBufferSize:DWORD,
pOutConnectStringLength:DWORD, DriverCompletion:DWORD
- ConnectionHandle 연결핸들을 지정한다
- hWnd어플리케이션의 핸들을 지정한다.만약에 NULL 값을 지정하면 추가정보에 대한
대화상자가 표시되지 않게 된다.(필요할 경우에 사용하기 바란다)- pInConnectString연결문자열에 대한 포인터를 지정한다. 연결문자열은 00H로 끝나는 아스키문자
열이다.(ASCIIZ)연결문자열에는 데이터소스와 ODBC드라이버등의 정보를 가지고
있게되며, 이정보를 기본으로 연결하게 된다.- InStringLength연결문자열의 길이를 지정한다.(대부분 이렇게 길이를 지정해준다)
- pOutConnectString실제로 작동 할 수 있는 완성된 연결문자열이 저장된 포인터를 지정한다.
이 완성 연결문자열 버퍼는 최소한 1,024Byte의 크기를 가져야 한다. 조금 혼란을
야기할 수 도 있겠다. 이미 연결문자열을 제공했는데 말이다. 이 프로시져의
특징중 하나가, 연결문자열이 완전하지 않을 경우 데이터소스 대화상자가 표시되고 사용자로 하여금 정확한 데이터소스를 설정할 기회를 준다고 했었다. 바로 그렇게 생성된 완전한 연결문자열을 저장할 버퍼를 지정하는 것이다. 여기에 저장된
완전한 연결문자열이 추후에 계속 사용되게 된다.- OutBufferSize 설명하지 않아도 알것이다, 상기의 연결문자열 버퍼의 크기를 지정한다. pOutConnectString 버퍼의 크기이다.
- pOutConnectStringLength완성된 연결 문자열 버퍼의 크기를 지정한다.실제값은 더블워드 크기로 ODBC 드라이버가
반환해준다.- DriverCompletionODBC매니져에게 정보설정을 할 수있는 플래그이다. 하지만 이것은 hWnd 인자에 따라 달라 질
수 있다.만약 데이터소스 완성 대화상자 플래그를 표시하고 싶지 않다면 다음과 같은 값을
설정하면 된다.
SQL_DRIVER_PROMPT 연결 문자열을 완성할 수 있는 대화상자
표시.SQL_DRIVER_COMPLETE
SQL_DRIVER_COMPLETE_REQUIRED프로그램에서 완전한 연결문자열을 생성을
하지 못했을 경우 대화상자 표시SQL_DRIVER_NOPROMPT 연결문자열 대화상자 표시 안함. - pInConnectString연결문자열에 대한 포인터를 지정한다. 연결문자열은 00H로 끝나는 아스키문자
코드샘플
.data
strConnect db "DBQ=c:\data\test.mdb;DRIVER={Microsoft Access Driver (*.mdb)};",0
.data?
buffer db 1024 dup(?)
OutStringLength dd ?
.code
.....
invoke SQLDriverConnect, hConn, hWnd, addr strConnect, sizeof strConnect, addr buffer, sizeof buffer, addr OutBufferLength, SQL_DRIVER_COMPLETE
::: 데이터소스 접속 해제 :::
성공적으로 데이터소스에 연결했고, 원하는 작업을 수행했다면, 반드시 연결을 해제
해주어야 한다. 연결후 실제 명령을 수행하는것은 다음 파트에서 설명한다.
더이상 데이터소스에 연결할 일이 없다면 SQLDisconnect 프로시져를 호출해서 명시적으로 접속을 해제 주어야 한다. 이 프로시져는 아주 간단하다. 연결핸들만 지정한다.
invoke SQLDisconnect, hConn
::: 연결 / 환경 핸들 해제 :::
데이터소스 연결이 성공적으로 해제되면, 이제는 연결 / 환경 핸들을 해제해주어야한다. 이것은 SQLFreeHandle 프로시저를 호출해서 수행된다. 이 프로시져는 ODBC 3.x 에서 처음 소개된 프로시져이다.2.x버전에서는 SQLFreeConnect, SQLFreeEnv,SQLFreeStmt.등의
별도 처리 프로시져로 호출 했을 것이다.
SQLFreeHandle proto HandleType:DWORD, Handle:DWORD
- HandleType두번째 인수에 지정한 핸들의 타입을 지정한다. SQLAllocHandle 타입과 같다.
- Handle해제하고 싶은 핸들을 지정한다.
예제:
invoke SQLFreeHandle, SQL_HANDLE_DBC, hConn
invoke SQLFreeHandle, SQL_HANDLE_ENV, hEnv