本教程中,我們將學習使用ODBC APIs的細節.
因為我們的程序並不與ODBC驅動程序直接通信,而是通過ODBC管理器來定義一系列APIs供你的程序調用以完成工作,所以我們需要包含odbc32.inc和odbc32.lib文件,當然還有windows.inc。
連接數據源需要以下幾步:
分配一個環境句柄(environment handle). 在進行每個ODBC任務(session)時僅需這樣做一次.一旦獲得了句柄,我們就可修改環境屬性來適合我們的需要。你可以把這想象為在DB工作中創建一個workspace.
確認將使用的ODBC的版本. 你可在ODBC 2.x版和3.x版間選擇.他們在很多方面存在不同,因此本步驟是必須的以使得ODBC管理器它將用何種語法與用戶程序通訊,及如何解釋用戶程序的命令.
分配一個連接句柄.這個步驟可看作創建一個空連接.我們還沒有指定使用那一個驅動程序,連接那一個數據庫.這些信息將在稍後來寫入.
建立一個連接.可通過調用ODBC函數來建立連接.
當連接完成時,必須通過以下步驟來關閉和銷毀它:
斷開與數據源的連接.
釋放連接句柄.
釋放環境句柄 (如果不再需要在這個環境中作更多連接)
分配一個句柄
在ODBC 3.x版本以前,我們需要調用很多獨立的函數來分配環境、連接和語句句柄(SQLAllocEnv, SQLAllocConnect, SQLAllocStmt).而在ODBC 3.x中, 這些函數被SQLAllocHandle所代替,語法如下:
SQLRETURN SQLAllocHandle( SQLSMALLINT HandleType,
SQLHANDLE InputHandle,
SQLHANDLE * OutputHandlePtr
);
看上去挺麻煩,簡化一下看看:
SQLAllocHandle proto HandleType:DWORD, InputHandle:DWORD, OutputHandlePtr:DWORD
SQLRETURN 被定義為SQLSMALLINT類型.而 SQLSMALLINT被定義為短整型,例如一個字(16 bits). 所以該函數的返回值在ax中,而不是 eax. 這是很重要的.但是Win32下函數的參數是通過32位堆棧來傳送的.即使這個參數只是一個字長(16位),它也應被擴展為32位.這就是為什麼HandleType被說明為雙字(dword)而不是字(word).看一下導入庫 odbc32.lib,SQLAllocHandle的入口是_SQLAllocHandle@12. 就是說這個函數的參數的組合長度為12字節(3 dwords).然而,這不是說C函數的原型不對. SQLAllocHandle會只用HandleType的底位字並忽略高位字.因此C函數原型是功能上(functionally)正確而我們的匯編函數原型反映了實際.
結束了SQL類型的討論,我們來看一看函數的參數和返回值。.
HandleType 是一個常數,定義了希望分配的句柄類型.可能值如下:
SQL_HANDLE_ENV 環境句柄(Environment handle)
SQL_HANDLE_DBC 連接句柄(Connection handle)
SQL_HANDLE_STMT 語句句柄(Statement handle)
SQL_HANDLE_DESC 描述符句柄(Descriptor handle)
描述符是一個數據集合描述了一個SQL語句的參數或一個結果集的列數, 視應用程序或驅動程序而定。
InputHandle 是指向父"文本"的句柄.就是說,如果你想分配一個連接句柄, 需要通過一個環境句柄因為連接將在那個環境的文本中建立.如果你想分配一個環境句柄,這個參數必須為SQL_HANDLE_NULL (注意SQL_HANDLE_NULL在windows.inc版本1.18及其以前版本中被不正確的定義為0L.你需要刪除掉"L"否則程序不會被編譯通過.這是我的錯,因為我負責修訂windows.inc中的 SQL/ODBC部分.) 因為環境沒有父文本.對於語句和描述符句柄,我們需要將連接句柄作為這個參數。
OutputHandlePtr 如果調用成功,將指向一個雙字,其中包含了被分配的句柄.
SQLAllocHandle 可能的返回值如下:
SQL_SUCCESS 函數成功完成.
SQL_SUCCESS_WITH_INFO 函數成功完成,但帶回非致命錯誤或警告.
SQL_ERROR 函數調用失敗.
SQL_INVALID_HANDLE 傳送給函數的句柄非法.
無論函數的調用成功還是失敗,我們都可通過調用SQLGetDiagRec或SQLGetDiagField函數來獲得更多的信息.它們與Win32 API中的GetLastError很相似.
例子:
.data?
hEnv dd ?
.code
invoke SQLAllocHandle, SQL_HANDLE_ENV, SQL_HANDLE_NULL, addr hEnv
.if ax==SQL_SUCCESS || ax==SQL_SUCCESS_WITH_INFO
選擇ODBC的版本
分配完環境句柄後,我們需要設置一個環境屬性SQL_ATTR_ODBC_VERSION以適當的值.設置環境屬性可通過調用函數SQLSetEnvAttr.你也許猜到了,還有類似的函數如 SQLSetConnectAttr和SQLSetStmtAttr. SQLSetEnvAttr原型如下:
SQLSetEnvAttr proto EnvironmentHandle:DWORD, Attribute:DWORD, ValuePtr:DWORD,
StringLength:DWORD
EnvironmentHandle. 與字面意思一樣, 它包含了要設置屬性的環境句柄.
Attribute. 這是一個常數,表示用戶需要設置的屬性.對我們而言,是SQL_ATTR_ODBC_VERSION.可以從MSDN中查看全部列表.
ValuePtr. 這個參數的意義由希望設置的屬性值決定.如果屬性值是32位的, 這個參數將被認為是想要設置的屬性值.如果屬性值是一個字符串或二進制緩沖區,它就被解釋為指向字符串或緩沖區的指針.如果我們指定了要設置的屬性為SQL_ATTR_ODBC_VERSION, 這個參數我們可以填入SQL_OV_ODBC3和SQL_OV_ODBC2這兩個可能值,分別對應ODBC 3.x和2.x.
StringLength. 由ValuePtr指向的值的長度. 如果這個值是字符串或二進制緩沖區,這個參數一定是合法的. 如果想設置的屬性是一個雙字,這個參數被忽略.因為 SQL_ATTR_ODBC_VERSION屬性包含一個雙字的值,我們可以只給它賦為NULL.
這個函數的返回值與SQLAllocHandle相同.
例子:
.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驅動程序來連接數據源.通過這三個ODBC函數來達成這個目標.它們為我們提供了好幾層"選擇".
SQLConnect Core 這是最簡單的函數。它只需要數據源名(DSN,Data source name)和可選的用戶名和密碼.它不提供任何GUI選項例如向用戶顯示一個對話框來提供更多信息。如果你已經有了需要使用的數據庫的DSN就可以使用這個函數.本文來自編程入門網
SQLDriverConnect Core 這個函數提供了較SQLConnect更多的選擇.我們可以連接一個沒有在系統信息內定義的數據源。如沒有DSN.另外,我們可以指定這個函數是否需要顯示一個對話框來為用戶提供更多信息.例如,如果用戶遺漏了數據庫的名字,它會指導ODBC驅動程序顯示一個對話框,讓用戶來選擇想連接的數據庫.
SQLBrowseConnect Level 1 這個函數允許在運行時(RunTime)枚舉數據源.比SQLDriverConnect更加靈活。因為可以多次順序調用SQLBrowseConnect,而每次提供給使用者更多的專用信息直到最後獲得需要的連接句柄.
我將先檢查SQLConnect函數.要使用 SQLConnect,你應先知道什麼是DSN. DSN是數據源名(Data Source Name)的縮寫,是一個唯一標識某數據源的字符串。一個DSN標識了一個包含了如何連接某一特定的數據源的信息的數據結構.這個信息包括要使用何種ODBC驅動程序及要連接哪個數據庫.我們可以通過控制面板中的32位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和DSN的長度。如果數據源不需要的話,用戶名和密碼就不是必須的.函數的返回值與SQLAllocHandle的返回值相同.
假設我們的系統中有一個叫做"Sales" 的DSN並且我們想連接這個數據源.我們可以這樣做:
.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 指向連接字符串的指針. 這是一個ASCIIZ字符串,格式由要連接的具體ODBC驅動程序描述.它描述了驅動程序名、數據源及其他附加屬性.連接字符串的具體描述請參見MSDN,這裡不再細述.
InStringLength 連接字符串的長度.
pOutConnectString 指向將要被填入完整連接字符串的緩沖區的指針.這個緩沖區將至少有1,024字節長.這聽上去使人困惑。事實上,我們提供的連接字符串會不完整,這時,ODBC驅動程序會提示用戶更多信息.接下來ODBC驅動程序會根據所有可能的信息創建一個完整的連接字符串並將其放入緩沖區。即使我們提供的連接字符串已經可以工作了,這個緩沖區也會填入更多的屬性值.這個參數的目的是我們可以保存完整連接字符串來為接下來的連接做准備。
OutBufferSize 由pOutConnectString指向的緩沖區的長度.
pOutConnectStringLength 指向一個雙字的指針,用來接收由ODBC驅動程序返回的完整連接字符串的長度。
DriverCompletion 一個標志用來指示ODBC管理器/驅動程序是否將提示用戶更多信息.但是,這個標志取決於是否在調用本函數時傳送了hWnd 參數一個窗口句柄。如果沒有,即使該標志被設置,ODBC管理器/驅動程序也不會提示用戶.可能值如下:
SQL_DRIVER_PROMPT ODBC驅動程序提示用戶輸入信息。驅動程序將利用這些信息來創建連接字符串.
SQL_DRIVER_COMPLETE
SQL_DRIVER_COMPLETE_REQUIRED 僅當用戶提供的連接字符串不完全時, ODBC驅動程序才會提示用戶.
SQL_DRIVER_NOPROMPT ODBC驅動程序將不會提示用戶.
例子:
.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提供的新函數.它替代了SQLFreeConnect, SQLFreeEnv及SQLFreeStmt函數. SQLFreeHandle語法如下:
SQLFreeHandle proto HandleType:DWORD, Handle:DWORD
HandleType 標識要銷毀句柄的類別的常數.可能值與 SQLAllocHandle中相同
Handle要銷毀的句柄.
For example:
invoke SQLFreeHandle, SQL_HANDLE_DBC, hConn
invoke SQLFreeHandle, SQL_HANDLE_ENV, hEnv