ODBCAPI開發(fā)教程_第1頁
ODBCAPI開發(fā)教程_第2頁
ODBCAPI開發(fā)教程_第3頁
ODBCAPI開發(fā)教程_第4頁
ODBCAPI開發(fā)教程_第5頁
已閱讀5頁,還剩58頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、ODBC API開發(fā)教程第 1 章介紹在文章的開頭做一個(gè)習(xí)慣性的介紹。本文從2002年11月開始寫,基本上在2002年12月時(shí)完成,當(dāng)時(shí)本來作為一本書的一個(gè)章節(jié),后來由于某些原因沒有完成該書。這段時(shí)間將本文內(nèi)容進(jìn)行了一些整理,放在網(wǎng)上希望能夠給大家一些幫助。本文的內(nèi)容主要是關(guān)于ODBC 的功能,所有內(nèi)容都與ODBC 3.X版本兼容。本文簡要介紹了ODBC的歷史和發(fā)展,也介紹了ODBC的基本的常用功能。大致包括:使用ODBC進(jìn)行數(shù)據(jù)庫連接利用ODBC直接執(zhí)行SQL語句ODBC光標(biāo)類型介紹利用滾動光標(biāo)或非滾動光標(biāo)進(jìn)行結(jié)果集查詢存儲過程的調(diào)用與參數(shù)綁定SQL語句的準(zhǔn)備執(zhí)行方式BLOB數(shù)據(jù)字段的查詢和

2、修改本文的數(shù)據(jù)庫利用了MS SQL Server,ODBC在使用時(shí)是與數(shù)據(jù)庫無關(guān)的所以所有例程都可以運(yùn)行在其他數(shù)據(jù)庫上,例如Oracle。其實(shí)利用Access數(shù)據(jù)庫來進(jìn)行練習(xí)也是可以的,但是由于Access不能支持存儲過程,所以我沒有使用Access 數(shù)據(jù)庫。由于例程代碼沒有找到,所以沒有就沒有辦法提供,但是文中的代碼都比較詳細(xì)而且有具體的解釋。書中有很多錯(cuò)誤和不足之處希望大家能夠容忍和包含,也歡迎來信指出。第 2 章 ODBC API訪問數(shù)據(jù)庫2.1 ODBC簡要介紹2.1.1 在沒有ODBC以前請?jiān)试S我將那時(shí)候成為第二黑暗時(shí)代,第一黑暗時(shí)代是沒有數(shù)據(jù)庫的時(shí)代。ODBC的出現(xiàn)結(jié)束了數(shù)據(jù)庫開發(fā)

3、的無標(biāo)準(zhǔn)時(shí)代。在沒有ODBC以前不同的數(shù)據(jù)庫的開發(fā)所采用的標(biāo)準(zhǔn)是不統(tǒng)一的。一般來講不同的數(shù)據(jù)庫廠商都有自己的數(shù)據(jù)庫開發(fā)包,這些開發(fā)包支持兩種模式的數(shù)據(jù)庫開發(fā):預(yù)編譯的嵌入模式(例如Oracle 的ProC,SQL Server的ESQL和API調(diào)用(例如Oracle的OCI。對于一個(gè)開發(fā)人員來講使用預(yù)編譯方式開發(fā)是極其痛苦的,我就有過這樣的經(jīng)歷,所有的SQL語句要寫在程序內(nèi)部,并且遵守一定的規(guī)則,然后由數(shù)據(jù)庫廠商的預(yù)編譯工具處理后形成C代碼,最后由C編譯器進(jìn)行編譯。預(yù)編譯的最大問題就在于無法動態(tài)的生成SQL語句,我想作為一個(gè)程序員是很難接受的。接下來的是使用API進(jìn)行開發(fā),和預(yù)編譯相比算是前進(jìn)

4、了一大步。數(shù)據(jù)庫廠商提供了開發(fā)包,你通過各種API函數(shù)就可以連接數(shù)據(jù)庫,執(zhí)行查詢、修改、刪除,操縱光標(biāo),執(zhí)行存儲過程等。對于程序員來講有了更多的自由,而且可以創(chuàng)建自己的開發(fā)包。但是這一切的開發(fā)只能針對同一種數(shù)據(jù)庫。Oracle的OCI是一個(gè)非常優(yōu)秀的C語言開發(fā)包,在ODBC中就在很多地方參照了OCI的設(shè)計(jì)。2.1.2 ODBC介紹ODBC(Open Database Connectivity是由微軟公司提出的一個(gè)用于訪問數(shù)據(jù)庫的統(tǒng)一界面標(biāo)準(zhǔn),隨著客戶機(jī)/服務(wù)器體系結(jié)構(gòu)在各行業(yè)領(lǐng)域廣泛應(yīng)用,多種數(shù)據(jù)庫之間的互連訪問成為一個(gè)突出的問題,而 ODBC成為目前一個(gè)強(qiáng)有力的解決方案。ODBC之所以能夠操

5、作眾多的數(shù)據(jù)庫,是由于當(dāng)前絕大部分?jǐn)?shù)據(jù)庫全部或部分地遵從關(guān)系數(shù)據(jù)庫概念,ODBC看待這些數(shù)據(jù)庫時(shí)正是著眼了這些共同點(diǎn)。雖然支持眾多的數(shù)據(jù)庫,但這并不意味ODBC會變得復(fù)雜,ODBC是基于結(jié)構(gòu)化查詢語言(SQL,使用SQL可大大簡化其應(yīng)用程序設(shè)計(jì)接口(API,由于ODBC 思想上的先進(jìn)性,而且沒有同類標(biāo)準(zhǔn)或產(chǎn)品與之競爭,因而越來越受到眾多廠家和用戶的青睞。目前,ODBC已經(jīng)成為客戶機(jī)/服務(wù)器系統(tǒng)中的一個(gè)重要支持技術(shù)。在1994年時(shí)ODBC有了第一個(gè)版本,這種名為Open Data Base Connection (開放式數(shù)據(jù)庫互連的技術(shù)很快通過了標(biāo)準(zhǔn)化并且得到各個(gè)數(shù)據(jù)庫廠商的支持。ODBC在當(dāng)時(shí)

6、解決了兩個(gè)問題,一個(gè)是在Windows 平臺上的數(shù)據(jù)庫開發(fā),另一個(gè)是建立一個(gè)統(tǒng)一的標(biāo)準(zhǔn),只要數(shù)據(jù)廠商提供的開發(fā)包支持這個(gè)標(biāo)準(zhǔn),那么開發(fā)人員通過ODBC開發(fā)的程序可以在不同的數(shù)據(jù)庫之間自由轉(zhuǎn)換。這對開發(fā)人員來說的確值得慶賀。ODBC參照了X/OpenData Management: SQL Call-Level Interface和ISO/ICE1995 Call-Level Interface標(biāo)準(zhǔn),在ODBC版本3.X中已經(jīng)完全實(shí)現(xiàn)了這兩個(gè)標(biāo)準(zhǔn)的所有要求。所以本書所有內(nèi)容都基于ODBC 3.0以上版本。最開始時(shí)支持ODBC的數(shù)據(jù)庫只有SQL Server,ACCESS,FoxPro,這些都時(shí)微

7、軟的產(chǎn)品,他們能夠支持ODBC一點(diǎn)也不奇怪,但是那時(shí)候Windows的圖形界面已經(jīng)成為了客戶端軟件最理想的載體,所以各大數(shù)據(jù)廠商也在不久后發(fā)布了針對ODBC的驅(qū)動程序。在Windows 3.X和Windows 95的時(shí)候ODBC并不作為系統(tǒng)的組成部分出現(xiàn),使用前必須另行安裝。但到了Windows 98的時(shí)候,當(dāng)你安裝好操作系統(tǒng)后,ODBC不需要另行安裝了,因?yàn)樗呀?jīng)成為了操作系統(tǒng)的一部分。這對很多拒絕ODBC的人來說又少了一個(gè)借口。作為一個(gè)程序員,至少是我,我實(shí)在找不出什么理由不為ODBC歡呼。此外ODBC 的結(jié)構(gòu)很簡單和清晰,學(xué)習(xí)和了解ODBC的機(jī)制和開發(fā)方法對學(xué)習(xí)ADO等其他的數(shù)據(jù)庫訪問技

8、術(shù)會有所幫助。2.1.3 ODBC結(jié)構(gòu)圖2.1顯示了ODBC的結(jié)構(gòu)。 圖2.1應(yīng)用程序(Application應(yīng)用程序本身不直接與數(shù)據(jù)庫打交道,主要負(fù)責(zé)處理并調(diào)用ODBC函數(shù),發(fā)送對數(shù)據(jù)庫的SQL請求及取得結(jié)果。驅(qū)動程序管理器(Driver Manager 驅(qū)動程序管理器是一個(gè)帶有輸入程序的動態(tài)鏈接庫(DLL,主要目的是加載驅(qū)動程序,處理ODBC調(diào)用的初始化調(diào)用,提供ODBC調(diào)用的參數(shù)有效性和序列有效性。驅(qū)動程序(Driver驅(qū)動程序是一個(gè)完成ODBC函數(shù)調(diào)用并與數(shù)據(jù)庫相互影響的DLL,這些驅(qū)動程序可以處理對于特定的數(shù)據(jù)的數(shù)據(jù)庫訪問請求。對于應(yīng)用驅(qū)動程序管理器送來的命令,驅(qū)動程序再進(jìn)行解釋形成

9、自己的數(shù)據(jù)庫所能理解的命令。驅(qū)動程序?qū)⑻幚硭械臄?shù)據(jù)庫訪問請求,對于應(yīng)用程序來講不需要關(guān)注所使用的是本地?cái)?shù)據(jù)庫還上網(wǎng)絡(luò)數(shù)據(jù)庫。2.1.4 ODBC的一致性O(shè)DBC 接口的優(yōu)勢之一為互操作性,程序設(shè)計(jì)員可以在不指定特定數(shù)據(jù)源情況下創(chuàng)建ODBC應(yīng)用程序。從應(yīng)用程序角度方面,為了使每個(gè)驅(qū)動程序和數(shù)據(jù)源都支持相同的 ODBC函數(shù)調(diào)用和SQL語句集,ODBC接口定義了一致性級別,即ODBC API 一致性和ODBC SQL語法一致性。SQL一致性規(guī)定了對SQL語句語法的要求,而API一致性規(guī)定了驅(qū)動程序需要實(shí)現(xiàn)的ODBC函數(shù)。一致性級別通過建立標(biāo)準(zhǔn)功能集來幫助應(yīng)用程序和驅(qū)動程序的開發(fā)者,應(yīng)用程序可以很容

10、易地確定驅(qū)動程序是否提供了所需的功能,驅(qū)動程序可被開發(fā)以支持應(yīng)用程序選項(xiàng),而不用考慮每個(gè)應(yīng)用程序的特定請求。2.2 使用ODBC進(jìn)行數(shù)據(jù)庫開發(fā)基本知識介紹2.2.1 建立ODBC DSNDSN (Data Source Name是用于指定ODBC與相關(guān)的驅(qū)動程序相對應(yīng)的一個(gè)入口,所有DSN的信息由系統(tǒng)進(jìn)行管理,一般來講當(dāng)應(yīng)用程序要使用ODBC訪問數(shù)據(jù)庫時(shí),就需要指定一個(gè)DSN以便于連接到一個(gè)指定的ODBC驅(qū)動程序。在控制面板中打開ODBC管理器,回看到如圖2.2的界面。 圖2.2DSN共分為三類:1.用戶DSN:對當(dāng)前登錄用戶可見,只能夠用于當(dāng)前計(jì)算機(jī)。2.系統(tǒng)DSN:對當(dāng)前系統(tǒng)上所有用戶可見

11、,包括NT中的服務(wù)。3.文件DSN:DSN信息存放在文件中,對能夠訪問到該文件的用戶可見。一個(gè)使用Access數(shù)據(jù)庫的DSN中的信息如下:ODBCDRIVER=Driver do Microsoft Access (*.mdbUID=adminDefaultDir=C:DBDBQ=C:DBchat.mdb對于文件DSN來講這些信息存放在文件中,對于用戶DSN和系統(tǒng)DSN來講這些信息存放在注冊表內(nèi)。你可以通過創(chuàng)建文件DSN來查看每種DSN對應(yīng)的信息內(nèi)容。下面的例子將告訴你如何添加一個(gè)SQL Server的DSN。 圖2.3圖2.3中的四個(gè)步驟分別是:1.選擇SQL Server作為驅(qū)動程序2.輸

12、入DSN名稱和SQL Server服務(wù)器地址或別名3.輸入用戶和口令進(jìn)行連接4.選擇默認(rèn)數(shù)據(jù)庫并完成2.2.2 使用ODBC所需要的文件你需要下面的文件:sql.h:包含有基本的ODBC API的定義。sqlext.h:包含有擴(kuò)展的ODBC的定義。odbc32.lib:庫文件。這些文件在VC6,VC7都已經(jīng)隨開發(fā)工具提供了,不需要另外安裝。此外所有的ODBC函數(shù)都以SQL開始,例如SQLExecute,SQLAllocHandle。2.2.3 SQL語句執(zhí)行方式介紹在ODBC中SQL語句的執(zhí)行方式分為兩種,直接執(zhí)行和準(zhǔn)備執(zhí)行。直接執(zhí)行是指由程序直接提供SQL語句,例如:Select * fro

13、m test_table 并調(diào)用SQLExecDirect執(zhí)行,準(zhǔn)備執(zhí)行是指先提供一個(gè)SQL語句并調(diào)用SQLPrepare,然后當(dāng)語句準(zhǔn)備好后調(diào)用SQLExecute執(zhí)行前面準(zhǔn)備好的語句。準(zhǔn)備執(zhí)行多用于數(shù)據(jù)插入和數(shù)據(jù)刪除,在進(jìn)行準(zhǔn)備時(shí)將由ODBC驅(qū)動程序?qū)φZ句進(jìn)行分析,在實(shí)際執(zhí)行時(shí)可以避免進(jìn)行SQL語句分析所花費(fèi)的時(shí)間,所以在進(jìn)行大批量數(shù)據(jù)操作時(shí)速度會比直接執(zhí)行有明顯改善。在后面的章節(jié)中我會詳細(xì)介紹準(zhǔn)備執(zhí)行與行列綁定與參數(shù)替換的用法。2.2.4 獲取SQL語句執(zhí)行的結(jié)果對于SQL查詢語句,ODBC會返回一個(gè)光標(biāo),與光標(biāo)對應(yīng)的是一個(gè)結(jié)果集合(可以理解為一個(gè)表格。開發(fā)人員利用光標(biāo)來瀏覽所有的結(jié)果,

14、你可以利用ODBC API 函數(shù)移動光標(biāo),并且獲取當(dāng)前光標(biāo)指向的行的列字段的數(shù)值。此外還可以通過光標(biāo)來對光標(biāo)當(dāng)前所指向的數(shù)據(jù)進(jìn)行修改,而修改會直接反映到數(shù)據(jù)庫中。對于數(shù)據(jù)更新語句,如插入,刪除和修改,在執(zhí)行后可以得到當(dāng)前操作所影響的數(shù)據(jù)的行數(shù)。2.2.5 程序執(zhí)行的基本流程圖 圖2.4圖2.4中是一個(gè)基本的使用ODBC API的一個(gè)流程,你現(xiàn)在并不理解上面所有的函數(shù)的作用,這沒有關(guān)系。但希望能夠通過這幅圖給你一個(gè)最初的映象,那就是使用ODBC API開發(fā)并不復(fù)雜。2.2.6 數(shù)據(jù)類型定義在使用ODBC開發(fā)時(shí)一個(gè)重要的問題就是數(shù)據(jù)轉(zhuǎn)換的問題,在ODBC中存在下面的幾類數(shù)據(jù):數(shù)據(jù)庫中SQL語言表達(dá)

15、數(shù)據(jù)的類型ODBC中表達(dá)數(shù)據(jù)的類型C語言中表達(dá)數(shù)據(jù)的類型在程序運(yùn)行過程中數(shù)據(jù)需要經(jīng)歷兩次轉(zhuǎn)換:C語言的數(shù)據(jù)或結(jié)構(gòu)類型與ODBC的數(shù)據(jù)類型的轉(zhuǎn)換,ODBC與SQL間數(shù)據(jù)類型的轉(zhuǎn)換。所以O(shè)DBC所定義的數(shù)據(jù)類型起到了中間橋梁的作用,在ODBC的驅(qū)動程序調(diào)用自己的DBMS數(shù)據(jù)庫訪問接口時(shí)就需要對數(shù)據(jù)類型進(jìn)行轉(zhuǎn)換。我們所需要關(guān)注的是C語言的數(shù)據(jù)類型和 ODBC數(shù)據(jù)類型間的轉(zhuǎn)換關(guān)系。從下圖中可以看到ODBC中定義的數(shù)據(jù)類型和SQL語言中數(shù)據(jù)類型的對應(yīng)關(guān)系,所以通過下表我們可以將ODBC和SQL語言間的數(shù)據(jù)一一對應(yīng),在后面的文字中我們不再區(qū)分ODBC數(shù)據(jù)類型和SQL語言數(shù)據(jù)類型。 圖2.5使用C/C+語言

16、開發(fā),那么必定會在與ODBC語言間存在數(shù)據(jù)的轉(zhuǎn)換的問題,因?yàn)镺DBC所存在的一些數(shù)據(jù)類型在C語言中是不存在的。在ODBC以宏定義的方式定義了C語言和ODBC中使用的數(shù)據(jù)類型: 圖2.6所以在ODBC的開發(fā)過程中不要使用int , float 之類的C語言的實(shí)際類型來定義變量而應(yīng)該使用ODBC定義的數(shù)據(jù)類型來定義變量,如:SQLINTEGER, SQLFLOAT。2.2.7 ODBC句柄ODBC中的句柄分為三類:環(huán)境句柄,數(shù)據(jù)庫連接句柄,SQL語句句柄。通過圖2.4看出,在使用ODBC功能時(shí)必須先申請環(huán)境句柄,然后在環(huán)境句柄的基礎(chǔ)上創(chuàng)建數(shù)據(jù)庫連接,最后在數(shù)據(jù)連接的基礎(chǔ)上執(zhí)行SQL語句。2.3 為

17、本章的例程創(chuàng)建DSN與數(shù)據(jù)庫表為了后面的例子能夠順利執(zhí)行,請創(chuàng)建一個(gè)名稱為“test”的DSN,并且使用下面的語句在數(shù)據(jù)庫中創(chuàng)建表和插入基本的數(shù)據(jù),這個(gè)例子和以后的例子中我們使用SQL Server作為數(shù)據(jù)庫,你需要連接到SQL Server上執(zhí)行下面的語句來創(chuàng)建表和插入數(shù)據(jù)。Create table test_t1(iID int primary key , tmJoin datetime , szName varchar(40 ,fTall float ;Insert into test_t1 values(1, '2002-1-1 15:25' , 'user_1

18、',1.56 ; Insert into test_t1 values(2, '2002-1-2 12:25' , 'user_2',1.53 ; Insert into test_t1 values(3, '2002-1-3 13:25' , 'user_3',1.76 ; 2.4 ODBC的基本功能介紹2.4.1 所需要了解的ODBC API2.4.1.1 SQLAllocHandle 創(chuàng)建ODBC句柄SQLRETURN SQLAllocHandle(SQLSMALLINT HandleType,SQLHANDLE I

19、nputHandle,SQLHANDLE * OutputHandlePtr;第一個(gè)參數(shù)HandleType的取值可以為:SQL_HANDLE_ENV:申請環(huán)境句柄。SQL_HANDLE_DBC:申請數(shù)據(jù)庫連接句柄。SQL_HANDLE_STMT:申請SQL語句句柄,每次執(zhí)行SQL語句都申請語句句柄,并且在執(zhí)行完成后釋放。第二個(gè)參數(shù)為輸入句柄,第三個(gè)參數(shù)為輸出句柄,也就是是你在第一參數(shù)指定的需要申請的句柄。根據(jù)1.2.7節(jié)的說明,在使用ODBC功能時(shí)必須先申請環(huán)境句柄,然后在環(huán)境句柄的基礎(chǔ)上創(chuàng)建數(shù)據(jù)庫連接,最后在數(shù)據(jù)連接的基礎(chǔ)上執(zhí)行SQL語句。所以可能的調(diào)用方式有三種。SQLAllocHand

20、le(SQL_HANDLE_ENV,NULL,&hEnv;SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER SQL_OV_ODBC3, SQL_IS_INTEGER;SQLAllocHandle(SQL_HANDLE_DBC,hEnv,&hDBC;SQLAllocHandle(SQL_HANDLE_STMT,hDBC,&hSTMT;請注意,在創(chuàng)建環(huán)境句柄后請務(wù)必調(diào)用:SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER SQL_OV_ODBC3, SQL_IS

21、_INTEGER;將ODBC設(shè)置成為版本3,否則某些ODBC API 函數(shù)不能被支持。2.4.1.2 ODBC API的返回值ODBC API的返回值定義為:SQLRETURN。在成功時(shí)返回值為:SQL_SUCCESS, SQL_SUCCESS_WITH_INFO;在失敗時(shí)返回錯(cuò)誤代碼。一點(diǎn)需要注意的是如果ODBC返回值為:SQL_SUCCESS_WITH_INFO并不表明執(zhí)行完全成功,而是表明執(zhí)行成功但是帶有一定錯(cuò)誤信息。當(dāng)執(zhí)行錯(cuò)誤時(shí)ODBC返回的是一個(gè)錯(cuò)誤信息的結(jié)果集,你需要遍歷結(jié)果集合中所有行,這點(diǎn)和后面講到的查詢SQL語句執(zhí)行結(jié)果集的思路很類似。在ODBC可以利用SQLGetDiagR

22、ec來得到錯(cuò)誤描述信息:SQLRETURN SQLGetDiagRec(SQLSMALLINT HandleType,SQLHANDLE Handle,SQLSMALLINT RecNumber,SQLCHAR * Sqlstate,SQLINTEGER * NativeErrorPtr,SQLCHAR * MessageText,SQLSMALLINT BufferLength,SQLSMALLINT * TextLengthPtr;RecNumber:指明需要得到的錯(cuò)誤狀態(tài)行,從1開始逐次增大。Sqlstate,NativeErrorPtr,MessageText:返回錯(cuò)誤狀態(tài),錯(cuò)誤代碼和

23、錯(cuò)誤描述。BufferLength:指定MessageText的最大長度。TextLengthPtr:指定返回的MessageText中有效的字符數(shù)。函數(shù)的返回值可能為:SQL_SUCCESS,SQL_SUCCESS_WITH_INFO,SQL_ERROR, SQL_INVALID_HANDLE, SQL_NO_DATA。在沒有返回錯(cuò)誤的情況下你需要反復(fù)調(diào)用此函數(shù),并順次增大RecNumber參數(shù)的值,直到函數(shù)返回SQL_NO_DATA,以得到所有的錯(cuò)誤描述。示例,得到STMT句柄上的錯(cuò)誤信息:SQLCHAR SqlState6,SQLStmt100,MsgSQL_MAX_MESSAGE_LE

24、NGTH;SQLINTEGER NativeError;SQLSMALLINT i, MsgLen;int i = 1;while (rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState,&NativeError, Msg, sizeof(Msg, &MsgLen != SQL_NO_DATA/顯示錯(cuò)誤的代碼i+;下面的函數(shù)來自MS文檔,用于顯示一個(gè)錯(cuò)誤的詳細(xì)情況,你可以在你的程序中直接使用:void ProcessLogMessages(SQLSMALLINT plm_handle_type,/出現(xiàn)錯(cuò)誤時(shí)所使用的ODB

25、C句柄類型,取值為:SQL_HANDLE_ENV ,SQL_HANDLE_DBC ,SQL_HANDLE_STMTSQLHANDLE plm_handle, /出現(xiàn)錯(cuò)誤時(shí)所使用的ODBC句柄char *logstring, /標(biāo)題字符串int ConnInd /指明句柄是否為DBC句柄RETCODE plm_retcode = SQL_SUCCESS;UCHAR plm_szSqlStateMAXBUFLEN = "",plm_szErrorMsgMAXBUFLEN = ""SDWORD plm_pfNativeError = 0L;SWORD plm_

26、pcbErrorMsg = 0;SQLSMALLINT plm_cRecNmbr = 1;SDWORD plm_SS_MsgState = 0, plm_SS_Severity = 0;SQLINTEGER plm_Rownumber = 0;USHORT plm_SS_Line;SQLSMALLINT plm_cbSS_Procname, plm_cbSS_Srvname;SQLCHAR plm_SS_ProcnameMAXNAME, plm_SS_SrvnameMAXNAME;printf(logstring;while (plm_retcode != SQL_NO_DATA_FOUND

27、plm_retcode = SQLGetDiagRec(plm_handle_type, plm_handle, plm_cRecNmbr, plm_szSqlState, &plm_pfNativeError,plm_szErrorMsg, MAXBUFLEN - 1, &plm_pcbErrorMsg;/ Note that if the application has not yet made a/ successful connection, the SQLGetDiagField/ information has not yet been cached by ODBC

28、/ Driver Manager and these calls to SQLGetDiagField/ will fail.if (plm_retcode != SQL_NO_DATA_FOUND if (ConnInd plm_retcode = SQLGetDiagField(plm_handle_type, plm_handle, plm_cRecNmbr,SQL_DIAG_ROW_NUMBER, &plm_Rownumber,SQL_IS_INTEGER,NULL;plm_retcode = SQLGetDiagField(plm_handle_type, plm_handl

29、e, plm_cRecNmbr,SQL_DIAG_SS_LINE, &plm_SS_Line,SQL_IS_INTEGER,NULL;plm_retcode = SQLGetDiagField(plm_handle_type, plm_handle, plm_cRecNmbr,SQL_DIAG_SS_MSGSTATE, &plm_SS_MsgState,SQL_IS_INTEGER,NULL;plm_retcode = SQLGetDiagField(plm_handle_type, plm_handle, plm_cRecNmbr, SQL_DIAG_SS_SEVERITY,

30、 &plm_SS_Severity,SQL_IS_INTEGER,NULL;plm_retcode = SQLGetDiagField(plm_handle_type, plm_handle, plm_cRecNmbr, SQL_DIAG_SS_PROCNAME, &plm_SS_Procname,sizeof(plm_SS_Procname,&plm_cbSS_Procname;plm_retcode = SQLGetDiagField(plm_handle_type, plm_handle, plm_cRecNmbr, SQL_DIAG_SS_SRVNAME, &a

31、mp;plm_SS_Srvname,sizeof(plm_SS_Srvname,&plm_cbSS_Srvname;printf("szSqlState = %sn",plm_szSqlState;printf("pfNativeError = %dn",plm_pfNativeError; printf("szErrorMsg = %sn",plm_szErrorMsg;printf("pcbErrorMsg = %dnn",plm_pcbErrorMsg; if (ConnInd printf(&quo

32、t;ODBCRowNumber = %dn", plm_Rownumber;printf("SSrvrLine = %dn", plm_Rownumber;printf("SSrvrMsgState = %dn",plm_SS_MsgState; printf("SSrvrSeverity = %dn",plm_SS_Severity; printf("SSrvrProcname = %sn",plm_SS_Procname; printf("SSrvrSrvname = %snn",

33、plm_SS_Srvname; plm_cRecNmbr+; /Increment to next diagnostic record. / End while.2.4.1.3 SQLConnect 連接數(shù)據(jù)庫SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR * ServerName,SQLSMALLINT NameLength1,SQLCHAR * UserName,SQLSMALLINT NameLength2,SQLCHAR * Authentication,SQLSMALLINT NameLength3;ConnectionHa

34、nlde:為DBC句柄,也就是前面提到到利用: SQLAllocHandle(SQL_HANDLE_DBC,hEnv,&hDBC;申請的句柄。ServerName:為ODBC的DSN名稱。NameLength1:指明參數(shù)ServerName數(shù)據(jù)的長度。UserName:數(shù)據(jù)庫用戶名。NameLength2:指明參數(shù)UserName數(shù)據(jù)的長度。Authentication:數(shù)據(jù)庫用戶密碼。NameLength3:指明參數(shù)Authentication數(shù)據(jù)的長度。關(guān)于ServerName,UserName,Authentication參數(shù)長度可以直接指定也可以指定為SQL_NTS表明參數(shù)是以

35、NULL字符結(jié)尾。示例代碼:retcode = SQLConnect(hdbc, (SQLCHAR* "odbc_demo", SQL_NTS,(SQLCHAR* "user", SQL_NTS, (SQLCHAR* "password", SQL_NTS;2.4.1.4 SQLExecDirect 直接執(zhí)行SQL語句SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle,SQLCHAR * StatementText,SQLINTEGER TextLength;StatementHandle

36、:SQL語句句柄,也就是前面提到的利用:SQLAllocHandle(SQL_HANDLE_STMT,hDBC,&hSTMT;申請的句柄。StatementText:SQL語句。TextLength:參數(shù)StatementText的長度,可以使用SQL_NTS表示字符串以NULL 字符結(jié)尾。如果函數(shù)執(zhí)行成功,你將會得到一個(gè)結(jié)果集,否則將返回錯(cuò)誤信息。SQLExecDirect函數(shù)除可以執(zhí)行 Select 語句外,還可以執(zhí)行Insert,Update, Delete 語句,在執(zhí)行修改SQL語句后可以利用SQLRowCount 函數(shù)來得到被更新的記錄的數(shù)量。2.4.1.5 SQLFetch

37、 移動光標(biāo)SQLRETURN SQLFetch(SQLHSTMT StatementHandle;在你調(diào)用SQLExecDirect執(zhí)行SQL語句后,你需要遍歷結(jié)果集來得到數(shù)據(jù)。StatementHandle是STMT句柄,此句柄必須是被執(zhí)行過。當(dāng)調(diào)用SQLFetch 函數(shù)后,光標(biāo)會被移動到下一條記錄處,當(dāng)光標(biāo)移動到記錄集的最后一條,函數(shù)將會返回SQL_NO_DATA。要遍歷所有的結(jié)果集可以利用下面的方法:while(SQL_NO_DATA != SQLFetch(hSTMT /移動光標(biāo),一直到集合末尾/得到結(jié)果2.4.1.6 SQLGetData 得到光標(biāo)處的某列的值SQLRETURN SQ

38、LGetData(SQLHSTMT StatementHandle,SQLUSMALLINT ColumnNumber,SQLSMALLINT TargetType,SQLPOINTER TargetValuePtr,SQLINTEGER BufferLength,SQLINTEGER * StrLen_or_IndPtr;StatementHanlde:STMT句柄。ClumnNumber:列號,以1開始。TargetType:數(shù)據(jù)緩沖區(qū)(TargetValuePtr的C語言數(shù)據(jù)類型,請參照圖2.6。BufferLength:數(shù)據(jù)緩沖區(qū)(TargetValuePtr的長度。StrLen_or

39、_IndPtr:返回當(dāng)前得到的字段的字節(jié)長度。下面是通過SQLFetch和SQLGetData得到記錄集的例子:/假設(shè) SQL = SELECT CUSTID, NAME, PHONE FROM CUSTOMERSSQLINTEGER sCustIDSQLCHAR szName50, szPhone50;SQLINTEGER cbName, cbAge, cbBirthday;/用來保存得到的數(shù)據(jù)的長度while (TRUE /循環(huán)得到所有行retcode = SQLFetch(hstmt;/移動光標(biāo)if (retcode = SQL_ERROR | retcode = SQL_SUCCESS

40、_WITH_INFO printf(“error SQLFetchn”;if (retcode = SQL_SUCCESS | retcode = SQL_SUCCESS_WITH_INFO /*得到當(dāng)前光標(biāo)處每列的值 */SQLGetData(hstmt, 1, SQL_C_ULONG, &sCustID, 0, &cbCustID;/此處并沒有指明BufferLength參數(shù)的值,是因?yàn)閿?shù)據(jù)類型是定長的LONG型SQLGetData(hstmt, 2, SQL_C_CHAR, szName, 50, &cbName;SQLGetData(hstmt, 3, SQL_

41、C_CHAR, szPhone, 50,&cbPhone;printf(out, "%5d %s %s", sCustID, szName, szPhone; else break;SQLGetData的另一個(gè)用處就是用于得到一些變長字段的實(shí)際長度,例如VARCHAR 字段,TEXT字段。例如:SQLGetData(hstmt, 2, SQL_C_CHAR, szName, 0, &cbName;當(dāng)你將 BufferLength 參數(shù)置為0,則會在 StrLen_or_IndPtr 參數(shù)中返回字段的實(shí)際長度。但請注意第四個(gè)參數(shù)必須是一個(gè)合法的指針,不能夠?yàn)镹

42、ULL。此外在得到字段的值時(shí)還存在一個(gè)數(shù)據(jù)類型轉(zhuǎn)換的問題,比如說數(shù)據(jù)庫內(nèi)的字段類型為:INTEGER,那么你可以使用SQL_C_INTEGER,SQL_C_CHAR,SQL_C_ULONG 數(shù)據(jù)類型來得到該字段的值。圖2.7就說明了所有可能存在的轉(zhuǎn)換關(guān)系。 圖2.7參考前面的圖2.5和圖2.6就可以看出ODBC可以在SQL的數(shù)據(jù)類型和C的數(shù)據(jù)類型間提供轉(zhuǎn)換。請注意我講解圖2.5時(shí)提到的時(shí)ODBC數(shù)據(jù)類型和SQL語言數(shù)據(jù)類型之間的對應(yīng)關(guān)系,而這里提到的是數(shù)據(jù)之間的轉(zhuǎn)換關(guān)系。圖中用圓點(diǎn)標(biāo)出的交叉點(diǎn)為允許的類型轉(zhuǎn)換,其中實(shí)心圓點(diǎn)標(biāo)出的是默認(rèn)的數(shù)據(jù)轉(zhuǎn)換類型,空心圓點(diǎn)標(biāo)出的是允許的數(shù)據(jù)轉(zhuǎn)換類型(允許并不

43、表明一定可以,例如 Char類型可以轉(zhuǎn)換為SQL_C_INTEGER,但是并不是總能成功,當(dāng)字符為123時(shí)可以轉(zhuǎn)換為整數(shù)123,而字符為odbc時(shí)就不能成功。例如數(shù)據(jù)庫中的Char,VarChar類型默認(rèn)都是對應(yīng)SQL_C_CHAR類型。你還可以看到所有的數(shù)據(jù)庫字段類型都可以轉(zhuǎn)換為 SQL_C_CHAR類型,例如整數(shù)123可以轉(zhuǎn)換為”123”,而浮點(diǎn)數(shù)1.23可以轉(zhuǎn)換為”1.23”,日期的2002年10月1日可以轉(zhuǎn)換為” 2002-10-1”。所以在初學(xué)ODBC并且對性能要求不是非常高時(shí)可以用字符類型來得到數(shù)據(jù)庫字段的值,這樣做會比較方便。2.4.1.7 SQLNumResultCols 得到

44、結(jié)果集中列數(shù)SQLRETURN SQLNumResultCols(SQLHSTMT StatementHandle,SQLSMALLINT * ColumnCountPtr;StatementHandle:STMT句柄ColumnCountPtr:返回列數(shù)2.4.1.8 SQLDescribeCol 得到結(jié)果集中列的描述SQLRETURN SQLDescribeCol(SQLHSTMT StatementHandle,SQLSMALLINT ColumnNumber,SQLCHAR * ColumnName,SQLSMALLINT BufferLength,SQLSMALLINT * Name

45、LengthPtr,SQLSMALLINT * DataTypePtr,SQLUINTEGER * ColumnSizePtr,SQLSMALLINT * DecimalDigitsPtr,SQLSMALLINT * NullablePtr;StatementHandle:STMT句柄。ColumnNumber:需要得到的列的序號,從1開始計(jì)算。ColumnName:得到列的名稱。BufferLength:指明ColumnName參數(shù)的最大長度。NameLengthPtr:返回列名稱的長度。DataTypePtr:得到列的ODBC數(shù)據(jù)類型,請參照圖2.5。ColumnSizePtr:得到列的長

46、度。DecimalDigitsPtr:當(dāng)該列為數(shù)字類型時(shí)返回小數(shù)點(diǎn)后數(shù)據(jù)的位數(shù)。NullablePtr:指明該列是否允許為空值。2.4.1.9 SQLRowCount 執(zhí)行SQL語句后得到影響的行數(shù)SQLRETURN SQLRowCount(SQLHSTMT StatementHandle,SQLINTEGER * RowCountPtr;你可以通過SQLExecDirect執(zhí)行SQL語句來插入,修改和刪除數(shù)據(jù),在執(zhí)行插入,修改和刪除的SQL語句后就可以通過SQLRowCount函數(shù)來得到被影響的數(shù)據(jù)的行數(shù)。Insert into test_t1 values(4, '2002-1-4

47、 11:25' , 'user_4',1.86 ; 2.5 ODBC的其他功能介紹2.5.1 ODBC連接句柄的參數(shù)設(shè)置在上一小節(jié)中提到了 SQLSetConnectAttr 這個(gè)函數(shù),這里需要對這個(gè)函數(shù)進(jìn)行一些簡單的講解,你可以通過調(diào)用 SQLSetConnectAttr 在數(shù)據(jù)庫連接建立或建立后設(shè)置連接的一些屬性。SQLSetConnectAttr的函數(shù)原型如下:SQLRETURN SQLSetConnectAttr(SQLHDBC ConnectionHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGE

48、R StringLength;ConnectionHandle:提供DBC連接句柄。Attribute:指定需要設(shè)置的屬性類型,在這里設(shè)置為值SQL_ATTR_AUTOCOMMIT。ValuePtr:提供參數(shù)值。StringLength:指定參數(shù)的長度,當(dāng)參數(shù)為整數(shù)是設(shè)置為SQL_IS_INTEGER,當(dāng)參數(shù)為字符串時(shí)設(shè)置為字符串長度或者為SQL_NTS 。這里講一下常用的參數(shù)Attribute可能的取值和ValuePtr對應(yīng)的取值: 2.5.2 ODBC語句句柄的參數(shù)設(shè)置如同數(shù)據(jù)庫連接句柄一樣,語句句柄也可以設(shè)置參數(shù)。函數(shù)為:SQLRETURN SQLSetStmtAttr(SQLHSTMT

49、 StatementHandle,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength;ConnectionHandle:提供STMT連接句柄。Attribute:指定需要設(shè)置的屬性類型,在這里設(shè)置為值SQL_ATTR_AUTOCOMMIT。ValuePtr:提供參數(shù)值。StringLength:指定參數(shù)的長度,當(dāng)參數(shù)為整數(shù)是設(shè)置為SQL_IS_INTEGER,當(dāng)參數(shù)為字符串時(shí)設(shè)置為字符串長度或者為SQL_NTS 。這里講一下常用的參數(shù)Attribute可能的取值和ValuePtr對應(yīng)的取值: 2.5.3 ODBC中使

50、用可以滾動的光標(biāo)2.5.3.1 ODBC光標(biāo)類型從上面的函數(shù)SQLSetStmtAttr可以看到我們在ODBC中可以使用不同的光標(biāo)類型,那么這些光標(biāo)之間有什么區(qū)別。向前光標(biāo):SQL_CURSOR_FORWARD_ONLY,光標(biāo)僅僅向前滾動。靜態(tài)光標(biāo):SQL_CURSOR_STATIC,結(jié)果集的數(shù)據(jù)是靜態(tài)的,這就是說明在執(zhí)行查詢后,返回的結(jié)果集的數(shù)據(jù)不會再改變,即使是有其他程序更新了數(shù)據(jù)庫中的記錄,結(jié)果集中的記錄也不會發(fā)生改變。動態(tài)光標(biāo):SQL_CURSOR_DYNAMIC,在光標(biāo)打開以后,當(dāng)結(jié)果集中的行所對應(yīng)的數(shù)據(jù)值發(fā)生變化時(shí),其變化能夠能夠反映到光標(biāo)所對應(yīng)的結(jié)果集上,這些變化包括:字段的修改

51、,添加,結(jié)果集中行的順序變化。但是請注意如果行別刪除則無法在當(dāng)前結(jié)果集中反映出,因?yàn)楸粍h除的行不再出現(xiàn)在當(dāng)前的結(jié)果集中。動態(tài)光標(biāo)所對應(yīng)的結(jié)果集在數(shù)據(jù)發(fā)生變化時(shí)會被重建。例如,假設(shè)動態(tài)光標(biāo)已獲取到了兩行,然后,另一應(yīng)用程序更新了這兩行中的一行,并刪除了另一行,如果動態(tài)游標(biāo)再試圖獲取那些行,它將不能檢測已刪除的行(因?yàn)楫?dāng)前結(jié)果集中只有一行,但是不要利用這個(gè)辦法去檢測被刪除的行,因?yàn)槌霈F(xiàn)這種情況還可能是因?yàn)樾械臄?shù)據(jù)被改變后不能再滿足查詢條件,而是返回已更新行的新值。鍵集光標(biāo):SQL_CURSOR_KEYSET_DRIVEN,和上面的動態(tài)光標(biāo)所不同的是鍵集光標(biāo)能夠檢測到行的刪除和修改,但是無法檢測到檢

52、測到行的添加和結(jié)果集順序變化。因?yàn)樵诠鈽?biāo)創(chuàng)建時(shí)就創(chuàng)建了整個(gè)結(jié)果集,結(jié)果集合中記錄和順序已經(jīng)被固定,這一點(diǎn)和靜態(tài)光標(biāo)一樣。所以鍵集光標(biāo)可以說是一種介于靜態(tài)光標(biāo)和動態(tài)光標(biāo)之間的光標(biāo)類型。需要說明的是并不是每個(gè)DBMS的ODBC驅(qū)動程序都能夠支持所有的這幾種光標(biāo),具體情況可以通過SQLGetInfo 函數(shù)進(jìn)行查詢。2.5.3.2 利用可滾動光標(biāo)進(jìn)行查詢前面介紹的SQLFetch函數(shù)只能夠讓光標(biāo)向前移動,但在很多時(shí)候我們需要光標(biāo)能夠前后移動。我們需要利用另一個(gè)函數(shù)SQLFetchScroll,但是再這之前請利用SQLSetStmtAttr正確設(shè)置光標(biāo)類型。SQLFetchScroll的原型如下:SQL

53、RETURN SQLFetchScroll(SQLHSTMT StatementHandle,SQLSMALLINT FetchOrientation,SQLINTEGER FetchOffset;與SQLFetch不同的是多了后面兩個(gè)參數(shù)。FetchOrientation:表明滾動的方式,允許的值如下: FetchOffset:表明光標(biāo)滾動的位置。光標(biāo)滾動后,獲取數(shù)據(jù)的方法和SQLFetch相同。滾動時(shí)如果指定的位置超出結(jié)果集區(qū)域會返回錯(cuò)誤。2.5.4 存儲過程的執(zhí)行與參數(shù)的綁定在ODBC中調(diào)用存儲過程需要遵守ODBC的約定,SQL語句的格式為:?=call procedure-name(p

54、arameter,parameter.在這里必須講解問號在SQL語句中的作用,問號在SQL語句中代表參數(shù)的含義,這個(gè)參數(shù)可以是作為輸入,也可以作為輸出或者是既輸入又輸出,參數(shù)在SQL語句執(zhí)行后進(jìn)行指定,后面的章節(jié)中會進(jìn)一步講解參數(shù)的用法。其中第一問號的作用是取得存儲過程的返回值,在執(zhí)行的過程中必須將此參數(shù)綁定到某一個(gè)變量,在執(zhí)行結(jié)束后被綁定的變量中就會被賦值。后面的參數(shù)可以是在SQL語句中直接指定,例如: call insert_this ( 1 , myName 也可以利用參數(shù)來指定例如: call insert_this ( 1 , ? 參數(shù)的值會在SQL語句執(zhí)行的過程中進(jìn)行指定。執(zhí)行存儲

55、過程直接利用SQLExecDirect API 函數(shù)就可以了。但是存儲過程中很多時(shí)候會返回結(jié)果,這些結(jié)果必須用參數(shù)的形式才能夠得到,所以下面要介紹一下如何利用參數(shù)綁定的方法來得到存儲過程的返回值,此外利用參數(shù)綁定還可以動態(tài)的向存儲過程提供參數(shù)。但是進(jìn)行參數(shù)綁定就需要使用另一個(gè)ODBC API:SQLRETURN SQLBindParameter(SQLHSTMT StatementHandle,SQLUSMALLINT ParameterNumber,SQLSMALLINT InputOutputType,SQLSMALLINT ValueType,SQLSMALLINT ParameterT

56、ype,SQLUINTEGER ColumnSize,SQLSMALLINT DecimalDigits,SQLPOINTER ParameterValuePtr,SQLINTEGER BufferLength,SQLINTEGER * StrLen_or_IndPtr;StatementHandle:執(zhí)行SQL語句STMT句柄。ParameterNumber:指明要將變量與第幾個(gè)參數(shù)綁定,從1開始計(jì)算。InputOutputType:指明是輸入還是輸出參數(shù)??梢匀≈档姆秶鸀?SQL_PARAM_INPUT,SQL_PARAM_OUTPUT ,SQL_PARAM_INPUT_OUTPUT。Va

57、lueType:指明用于和參數(shù)綁定的C語言數(shù)據(jù)類型。ParameterType:指明在存儲過程中ODBC數(shù)據(jù)類型。ColumnSize:指明接收數(shù)據(jù)的寬度,對于字符串和結(jié)構(gòu)需要指明數(shù)據(jù)的寬度,而對于普通的變量如SQLINTEGER,SQLFLOAT等設(shè)置為0就可以了。DecimalDigits :當(dāng)數(shù)據(jù)類型為SQL_NUMERIC,SQL_DECIMAL時(shí)指明數(shù)字小數(shù)點(diǎn)的精度,否則填0。ParameterValuePtr:在作為輸入?yún)?shù)指明參數(shù)的指針,在作為輸出參數(shù)時(shí)指明接收數(shù)據(jù)的變量指針。BufferLength:指明參數(shù)指針?biāo)赶虻木彌_區(qū)的字節(jié)數(shù)大小。對于字符串和結(jié)構(gòu)需要指明大小,而對于普通的變量如SQLINTEGER,SQLFLOAT等設(shè)置為0就可以了。StrLen_or_IndPtr:作為輸入?yún)?shù)時(shí)指明數(shù)據(jù)的字節(jié)數(shù)大小,對于普通的定長變量如SQLINTEGER,SQLFLOAT等設(shè)置為0就可以了,對于字符號串需要在此參數(shù)中指定字符串?dāng)?shù)據(jù)的長度,或者設(shè)置為SQL_NULL_DATA表明此參數(shù)為空值,或者設(shè)置為SQL_NTS表明字符串以NULL字符結(jié)尾,對于結(jié)構(gòu)需要指明結(jié)構(gòu)的長度。當(dāng)作為輸出參數(shù)時(shí),當(dāng)SQL執(zhí)行完畢后會在這個(gè)參數(shù)中返回拷貝的緩沖區(qū)的數(shù)據(jù)的字節(jié)數(shù)。2.5.4.1 例子一:調(diào)用含有輸出參數(shù)的存儲過程在S

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論