연결 과정
- ODBC Data Source 설정 참고)windows 10에서 ODBC data source 설정 방법
- DB에 연결
- Header 파일 include: sql.h , sqltypes.h , sqlext.h
- SQLAllocHandle(..): Environment handle (object) 할당
- SQLSetEnvAttr(..): Environment handle 설정
- SQLAllocHandle(..): Connection handle (object) 할당
- SQLSetConnectAttr(..): Connection handle 설정
- SQLConnect(..) (또는 SQLDriverConnect(..)): DB와 연결
- SQLAllocHandle(..): Statement handle (object) 할당
- (SQLSetStmtAttr(..): Statmenet handle 설정)
- statement 실행
- Query 결과 확인
- DB와의 연결 해제
- SQLFreeHandle(..): Statement handle 해제
- SQLDisconnect(..): DB 연결 해제
- SQLFreeHandle(..): Connection handle 해제
- SQLFreeHandle(..): Environment handle 해제
SQLDriverConnect(..)는 GetDesktopWindow() 사용해 windows.h 사용.
ODBC API에 param.로 char string을 전달 시 반드시 wchar 형으로 전달해야 함. 참고) wide character type (wchar_t) 란?
statement 실행
query 직접 입력
- SQLExecDirect(..): SQL 문 실행
querying의 반복 실행이 없는 경우 가장 적합한 방식.
prepared procedure
- SQLBindParameter(..): SQL statement의 param. marker에 버퍼를 bind.
- SQLPrepare(..): query 실행을 위한 SQL string을 준비.
- SQLExecute(..): prepared statement를 실행. 만약 param. marker가 statement 에 존재한다면 param. marker 변수의 현재 값을 사용.
query 결과 확인
query 결과로부터 데이터 추출
- SQLBindCol(..): 어플리케이션 데이터 버퍼를 result set의 column에 bind
- SQLFetch(..): result set의 다음 rowset의 데이터를 가져와서 bound된 모든 column에 대한 데이터를 리턴.
- SQLFetchScroll(..): result set의 다음 rowset의 데이터를 가져와서 bound된 모든 column에 대한 데이터를 리턴. rowset은 절대/상대/북마크 위치로 설정가능.
column-wise, row-wise 등 다양한 데이터 추출 방법이 존재. 참고) Retrieving Results (Advanced) |MSDN
result set 관련 정보 확인
- SQLDescribeCol(..): result set metadata를 알아내는데 사용
- SQLColAttribute(..): result set metadata를 알아내는데 사용
- SQLNumResultCols(..): result set의 column 개수를 반환
- SQLRowCount(..): UPDATE, INSERT, DELETE로 영향 받는 row의 개수를 반환.
SQLDecscribeCol VS SQLColAttribute SQLDecscribeCol 은 항상 정해진 5개의 정보를 리턴. SQLColAttribute 는 사용자가 지정한 정보 하나만을 리턴하는 대신에 더욱 다양한 정보에 대해 알아볼 수 있음. SQLDescribeCol and SQLColAttribute |MSDN
오류 처리
- SQLError(..): 오류나 스테이터스 정보를 반환
기타 함수
- SQLGetInfo(..): connection과 관련된 드라이버와 data source에 관한 전반적인 정보를 반환
code example
#include <iostream> | |
#include <Windows.h> | |
// Required header: | |
#include <sql.h> | |
#include <sqltypes.h> | |
#include <sqlext.h> | |
void HandleDiagnosticRecord(SQLHANDLE hHandle, | |
SQLSMALLINT hType, | |
RETCODE RetCode); | |
int main() | |
{ | |
SQLHENV hEnv; | |
SQLHDBC hDbc; | |
SQLHSTMT hStmt; | |
SQLWCHAR * dsnName = L"sqlODBC"; | |
SQLCHAR * userID = (SQLCHAR *)""; | |
SQLCHAR * pswd = (SQLCHAR *)""; | |
SQLWCHAR * stmt = L"select * from tb1"; | |
if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) != SQL_SUCCESS) { | |
std::cout << "Alloc handle error: SQL_HANDLE_ENV" << std::endl; | |
exit(1); | |
} | |
if (SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0) != SQL_SUCCESS) { | |
std::cout << "Set Attribute error: SQL_HANDLE_ENV" << std::endl; | |
exit(1); | |
} | |
if (SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc) != SQL_SUCCESS) { | |
std::cout << "Alloc handle error: SQL_HANDLE_DBC" << std::endl; | |
exit(1); | |
} | |
SQLSetConnectAttr(hDbc, 5, (SQLPOINTER)SQL_LOGIN_TIMEOUT, 0); | |
if (RETCODE errmsg = SQLConnect(hDbc, dsnName, SQL_NTS, (SQLWCHAR*)userID, SQL_NTS, (SQLWCHAR*)pswd, SQL_NTS) == SQL_ERROR) // ok | |
//if (RETCODE errmsg = SQLDriverConnect(hDbc, GetDesktopWindow(), L"", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE) == SQL_ERROR) // ok | |
// connection이 성공 시 SQL_SUCCESS, 혹은 SQL_SUCCESS_WITH_INFO 반환. | |
{ | |
std::cout << "DB connection error." << std::endl; | |
switch (errmsg) { | |
case SQL_ERROR: | |
std::cout << "SQL_ERROR" << std::endl; | |
break; | |
case SQL_SUCCESS_WITH_INFO: | |
std::cout << "SQL_SUCCESS_WITH_INFO" << std::endl; | |
break; | |
case SQL_INVALID_HANDLE: | |
std::cout << "SQL_INVALID_HANDLE" << std::endl; | |
break; | |
default: | |
std::cout << "etc error" << std::endl; | |
break; | |
} | |
HandleDiagnosticRecord(hDbc, SQL_HANDLE_DBC, errmsg); | |
exit(1); | |
} | |
SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt); | |
//RETCODE RetCode = SQLExecDirect(hStmt, (SQLWCHAR*)stmt, SQL_NTS); // error 42000: systax error (stmt should be given in wchar(L"~") type.) | |
//RETCODE RetCode = SQLExecDirect(hStmt, stmt, SQL_NTS); // ok (stmt type changed to wchar(L"~") type.) | |
RETCODE RetCode = SQLExecDirect(hStmt, L"SELECT * FROM tb1", SQL_NTS); // ok | |
// 성공 시 SQL_SUCCESS 반환 | |
switch (RetCode) | |
{ | |
case SQL_SUCCESS_WITH_INFO: | |
{ | |
std::cout << "SQL_SUCCESS_WITH_INFO" << std::endl; | |
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode); | |
// fall through | |
} | |
case SQL_SUCCESS: | |
{ | |
std::cout << "SQLExecDirect(..) success!" << std::endl; | |
SQLSMALLINT num; | |
std::cout << "SQLNumResultCols: " << SQLNumResultCols(hStmt, &num) << std::endl; | |
std::cout << "num: " << num << std::endl; | |
break; | |
} | |
case SQL_ERROR: | |
{ | |
std::cout << "SQL_ERROR" << std::endl; | |
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode); | |
break; | |
} | |
default: | |
fwprintf(stderr, L"Unexpected return code %hd!\n", RetCode); | |
} | |
SQLFreeHandle(SQL_HANDLE_STMT, hStmt); | |
SQLFreeHandle(SQL_HANDLE_DBC, hDbc); | |
SQLFreeHandle(SQL_HANDLE_ENV, hEnv); //End the connection | |
std::cout << "Program ends." << std::endl; | |
return 0; | |
} | |
void HandleDiagnosticRecord(SQLHANDLE hHandle, | |
SQLSMALLINT hType, | |
RETCODE RetCode) | |
{ | |
SQLSMALLINT iRec = 0; | |
SQLINTEGER iError; | |
WCHAR wszMessage[1000]; | |
WCHAR wszState[SQL_SQLSTATE_SIZE + 1]; | |
if (RetCode == SQL_INVALID_HANDLE) | |
{ | |
fwprintf(stderr, L"Invalid handle!\n"); | |
return; | |
} | |
while (SQLGetDiagRec(hType, | |
hHandle, | |
++iRec, | |
wszState, | |
&iError, | |
wszMessage, | |
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)), | |
(SQLSMALLINT *)NULL) == SQL_SUCCESS) | |
{ | |
// Hide data truncated.. | |
if (wcsncmp(wszState, L"01004", 5)) | |
{ | |
fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError); | |
} | |
} | |
} |
reference
- SQLBindCol Function Code Example |MSDN
- Sample ODBC Program |MSDN
- ODBC API Reference |MSDN
- Retrieving Results (Basic) |MSDN
- ODBC API |sonpadak naver blog
- [MFC로 구현하는 DB 프로그래밍] 2. DB의 다리 ODBC |zdnet
- Visual C++의 데이터 액세스
- Mysql API/C/C++ 연동하기 강좌 (7. ODBC를 이용한 mysql 연동하기) |티스토리
- CPP With ODBC (Open Database Connectivity) CPP Connection With A Database |dreamincode.net