2.2 應用ODBC API建立應用程序
雖然直接應用ODBC API編制應用程序相對來說較為繁瑣,但是,由於直接使用ODBC API編寫的程序相對要簡潔、高效。所以,我們有必要學習直接使用ODBC API編程。
一般地,編寫ODBC程序主要有以下幾個步驟:
分配ODBC環境
分配連接句柄
連接數據源
構造和執行SQL語句
取得執行結果
斷開同數據源的連接
釋放ODBC環境
2.21 分配ODBC環境
對於任何ODBC應用程序來說,第一步的工作是裝載驅動程序管理器,然後初始化ODBC環境,分配環境句柄。
首先,程序中聲明一個SQLHENV類型的變量,然後調用函數SQLAllocHandle,向其中傳遞分配的上述SQLHENV類型的變量地址和SQL_HANDLE_ENV選項。如下代碼所示:
SQLHENV henv;
SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);
執行該調用語句後,驅動程序分配一個結構,該結構中存放環境信息,然後返回對應於該環境的環境句柄。
2.22分配連接句柄
分配環境句柄後,在建立至數據源的連接之前,我們必須分配一個連接句柄,每一個到數據源的連接對應於一個連接句柄。
首先,程序定義了一個SQLHDBC類型的變量,用於存放連接句柄,然後調用SQLAllocHandle函數分配句柄。如下代碼所示:
SQLHDBC hdbc;
SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);
henv為環境句柄。
2.23 連接數據源
當連接句柄分配完成後,我們可以設置連接屬性,所有的連接屬性都有缺省值,但是我們可以通過調用函數SQLSetConnectAttr()來設置連接屬性。用函數SQLGetConnectAttr()獲取這些連接屬性。
函數格式如下:
SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
SQLRETURN SQLGetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength);
應用程序可以根據自己的需要設置不同的連接屬性。
完成對連接屬性的設置之後,就可以建立到數據源的連接了。對於不同的程序和用戶接口,可以用不同的函數建立連接:SQLConnect、SQLDriverConnect、SQLBrowseConnect。
SQLConnect
該函數提供了最為直接的程序控制方式,我們只要提供數據源名稱、用戶ID和口令,就可以進行連接了。
函數格式:
SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);
參數:
ConnectionHandle 連接句柄
ServerName 數據源名稱
NameLength1 數據源名稱長度
UserName 用戶ID
NameLength2 用戶ID長度
Authentication 用戶口令
NameLength3 用戶口令長度
返回值:
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.
成功返回SQL_SUCCESS,如果返回值為SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函數SQLGetDiagRec獲取相應SQLSTATE的值。
下面的代碼演示了如何使用ODBC API的SQLConnect函數建立同數據源SQLServer的連接。
#include “sqlext.h”
SQLHENV henv;;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
/*Allocate environment handle */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Set the ODBC version environment attribute */
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Allocate connection handle */
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Set login timeout to 5 seconds. */
SQLSetConnectAttr(hdbc, (void*)SQL_LOGIN_TIMEOUT, 5, 0);
/* Connect to data source */
retcode = SQLConnect(hdbc, (SQLCHAR*) "Sales", SQL_NTS,
(SQLCHAR*) "JohnS", SQL_NTS,
(SQLCHAR*) "Sesame", SQL_NTS);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
/* Allocate statement handle */
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Process data */;
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
SQLDriveConnect
函數SQLDriveConnect用一個連接字符串建立至數據源的連接。它可以提供比SQLConnect函數的三個參數更多的信息,可以讓用戶輸入必要的連接信息。
如果連接建立,該函數返回完整的字符串,應用程序可使用該連接字符串建立另外的連接。
函數格式:
SQLRETURN SQLDriverConnect(SQLHDBC ConnectionHandle,SQLHWND WindowHandle,SQLCHAR InConnectionString,SQLSMALLINT StringLength1,SQLCHAR OutConnetionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr,SQLSMALLINT DriverCompletion);
參數:
ConnectionHandle 連接句柄
WindowHandle 窗口句柄,應用程序可以用父窗口的句柄,或用NULL指針
InConnectionString 連接字符串長度
OutConnectionString 一個指向連接字符中的指針
BufferLength 存放連接字符串的緩沖區的長度
StringLength2Ptr 返回的連接字符串中的字符數
DriverCompletion 額外連接信息,可能取值有:SQL_DRIVER_PROMPT,
SQL_DRIVER_COMPLETE,
SQL_DRIVER_COMPLETE_REQUIRED, or
SQL_DRIVER_NOPROMPT.
返回值:
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.
成功返回SQL_SUCCESS,如果返回值為SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函數SQLGetDiagRec獲取相應SQLSTATE的值。
SQLBrowseConnect
函數SQLBrowseConnect支持以一種迭代的方式獲取到數據源的連接,直到最後建立連接。它是基於客房機/服務器的體系結構,因此,本地數據庫不支持該函數。
一般,我們提供部分連接信息,如果足以建立到數據源的連接,則成功建立連接,否則返回SQL__NEED__DATA,並在OutConnectionString參數中返回所需要的信息。
函數格式:
SQLRETURN SQLBrowseConnect(SQLHDBC ConnectionHandle,SQLCHAR* InConnectionString,SQLSAMLLINT StringLength1,SQLCHAR* OutConnectionString,SQLSMALLINT BufferLength,SQLSMALLINT *StringLength2Ptr);
參數:
ConnectionHandle 連接句柄
InConnectionString 指向輸出字符串的指針
StringLength1 輸出字符串的指針長度
OutConnectionString 指向輸出字符串的指針
BufferLength 用於存放輸出字符串的緩沖區的長度
StringLength2Ptr 實際返回的字符串的長度
返回值:
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.
成功返回SQL_SUCCESS,如果返回值為SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函數SQLGetDiagRec獲取相應SQLSTATE的值。
下面的代碼講述了如何使用ODBC API的SQLBrowseConnect函數建立同數據源的連接。
#define BRWS_LEN 100SQLHENV
henv;SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];
SQLSMALLINT cbConnStrOut;/* Allocate the environment handle. */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Set the version environment attribute. */
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Allocate the connection handle. */
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Call SQLBrowseConnect until it returns a value other than */
/* SQL_NEED_DATA (pass the data source name the first time). */
/* If SQL_NEED_DATA is returned, call GetUserInput (not */
/* shown) to build a dialog from the values in szConnStrOut. */
/* The user-supplIEd values are returned in szConnStrIn, */
/* which is passed in the next call to SQLBrowseConnect. */
lstrcpy(szConnStrIn, "DSN=Sales"); do {
retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,
szConnStrOut, BRWS_LEN, &cbConnStrOut);
if (retcode == SQL_NEED_DATA)
GetUserInput(szConnStrOut, szConnStrIn);
} while (retcode == SQL_NEED_DATA);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
/* Allocate the statement handle. */
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
/* Process data after successful connection */ ...;
SQLFreeHandle(SQL_HANDLE_STMT, hstmt); }
SQLDisconnect(hdbc); } }
SQLFreeHandle(SQL_HANDLE_DBC, hdbc); }}
SQLFreeHandle(SQL_HANDLE_ENV, henv);