天天看點

Oracle官方OCI(Oracle Call Interface)文檔翻譯Oracle官方OCI(Oracle Call Interface)文檔翻譯 

Oracle官方OCI(Oracle Call Interface)文檔翻譯 

                     -----Oracle8i開始的句柄方式的OCI

               該文檔的pdf格式文檔已經上傳至百度文庫,網址是http://wenku.baidu.com/view/b7819b8c84868762caaed5f8?fr=prin ,可以到該網址下載下傳該文檔。

OCI學習資料

--Oracle8及以後版本的OCI

1.     簡介

Oracle調用接口(Oracle Call Interface)是一個讓我們通過函數調用來通路Oracle資料庫和

控制SQL語句執行各個階段的應用程式程式設計接口(API)。OCI支援C和C++的資料類型、調用慣例、文法和語義。

1.1    建立一個OCI應用程式

我們編譯和連接配接一個OCI程式的方法與編譯和連接配接一個非資料庫應用程式的方法相同。

不需要獨立的預處理或者預編譯步驟。

1.2    OCI的組成部分

OCI具有如下功能:

·能夠安全地支援大量使用者的靈活的、多線程API集合。

·為管理資料庫通路、處理SQL語句和管理Oracle資料庫對象的SQL通路函數。

·管理Oracle類型的資料屬性的資料類型映射和操作函數。

·不經SQL語句直接向資料庫加載資料的資料加載函數。

1.3    封裝的接口

所有的OCI函數使用的資料結構都以被稱為句柄的不透明的接口之形式封裝。句柄是指

向OCI庫配置設定的儲存着上下文資訊、連接配接資訊、錯誤資訊或者關于SQL及PL/SQL的綁定資訊的不透明指針。用戶端配置設定一定類型的句柄,通過已經定義好的接口來填充一個或者多個句柄,并通過這些句柄向伺服器發送請求。應用程式可以通過通路函數來通路句柄中包含的相關資訊。

2.     OCI基本程式設計

  這部分介紹OCI程式設計中涉及到的基本概念。

2.1    OCI程式設計概要

一個OCI應用程式的基本目标就是代表多個使用者進行資料庫操作。

OCI使用以下基本程式設計順序:

1.      初始化OCI程式設計環境和線程。

2.      配置設定必要的句柄,并且設定伺服器連接配接和使用者會話。

3.      通過在伺服器上執行SQL語句來交換資料,并且執行必要的應用程式資料處理。

4.      執行準備好的語句或者準備即将要執行的語句。

5.      終止使用者會話并且斷開伺服器連接配接。

6.      釋放句柄。

圖2-1顯示了一個OCI應用程式的程式設計步驟。

     圖2-1

       這幅圖及其所列出的步驟提供了一個OCI程式設計步驟的簡單概括。根據程式的功能,變化是完全可能發生的。包含管理多個會話、事務和使用對象的更複雜的OCI應用程式需要另外的步驟。

       所有的OCI函數調用都在一個環境中執行。在一個OCI程序中可以有多個環境。如果一個環境需要任何程序級别的初始化,則其自動進行。

       注意:在一個OCI應用程式中可以有多個活動連接配接和語句。

2.2    OCI資料結構

  句柄(Handles)和描述符(descriptors)是OCI應用程式中定義的不透明的資料結構。它們可以被直接配置設定、通過特殊的配置設定函數或者可以被OCI函數隐式地配置設定。

  7.X 更新注意:以前寫過7.XOCI應用程式的程式員必須熟悉這些被大多數OCI函數使用的資料結構。

  句柄和描述符儲存有關資料、連接配接、或者應用程式行為的資訊。

2.3    句柄

  幾乎每一個OCI函數的參數清單中都包含有一個或者多個句柄。一個句柄是一個指向一個OCI庫配置設定的存儲區域的不透明的指針。我們使用句柄來儲存上下文資訊或者連接配接資訊,(例如,一個環境或者服務句柄),或者它可以儲存關于OCI函數或者資料的資訊(例如,一個錯誤句柄或者描述句柄)。句柄可以使程式設計更簡單,因為OCI庫會維持這些資料而不是應用程式。

  大多數OCI應用程式需要使用句柄中的資訊。擷取屬性值和設定屬性值的OCI函數,OCIAttrGet()和OCIAttrSet(),擷取和設定這些資訊。

  表2-1 列出了OCI中定義的句柄。并列出了與每一種句柄類型相對應的C資料類型和OCI函數中使用的用來識别OCI調用中的句柄類型的句柄類型常量。

  表2-1  OCI句柄類型

  配置設定和釋放句柄

  我們的應用程式要為一個特定的環境句柄配置設定所有的句柄(除了綁定句柄bind handle、定義句柄define handle和線程句柄thread handles)。我們把環境句柄作為一個參數傳遞至句柄配置設定函數。然後,被配置設定的句柄就特定于那個特定的環境。

  綁定句柄和定義句柄是為一個語句句柄配置設定的,并且包含了關于那個句柄所代表的語句的資訊。

  注意:綁定句柄和定義句柄是由OCI庫隐式配置設定的,不需要使用者配置設定。

  圖2-2 顯示了不同類型的句柄的層次

     圖2-2 句柄的層次

  環境句柄是由OCIEnvCreate()或者OCIEnvNlsCreate()函數配置設定和初始化的,所有的OCI程式都需要執行它們中的任一個。

  所有的使用者配置設定的句柄都通過OCI句柄配置設定函數來初始化,即OCIHandleAlloc()函數。

  句柄類型包括:線程句柄、描述句柄、語句句柄、服務上下文句柄、錯誤句柄和伺服器句柄等。

  線程句柄通過OCIThreadHndInit()函數配置設定。

  一個應用程式必須釋放所有的不再使用的句柄。OCIHandleFree()函數釋放所有的句柄。

  注意:當一個父句柄被釋放後,所有與之相連的子句柄也被釋放并且再也不能被使用。例如,當一個語句句柄釋放後,任何與之相連的綁定和定義句柄也都被釋放。

  句柄減少了對全局變量的需要。句柄也使錯誤報告更容易。一個錯誤句柄用來傳回錯誤和診斷資訊。

2.3.1         環境句柄

環境句柄提供了一個所有的OCI函數被調用的上下文。每一個環境句柄包含一個支援快

速通路的記憶體緩存。所有的環境句柄下的記憶體配置設定都是通過這個緩存完成的。如果多個線程想要在同一個環境句柄下配置設定記憶體,則它們對緩存的通路是序列化的。當多個線程共享一個單獨的環境句柄時,它們會阻塞對緩存的通路。

         環境句柄作為OCIHandleAlloc()函數的parent參數來配置設定其他句柄類型。綁定句柄和定義句柄是隐式配置設定的。

2.3.2         錯誤句柄

錯誤句柄作為一個參數傳遞至大多數OCI函數。錯誤句柄維持着關于一個OCI操作中所發生的錯誤的資訊。如果一個函數調用中發生了一個錯誤,錯誤句柄可以傳給OCIErrorGet()函數來擷取關于那個錯誤的額外資訊。

由于大多數OCI函數都需要一個錯誤句柄作為一個參數,配置設定錯誤句柄是一個OCI應用程式中的前幾個步驟之一。

2.3.3          服務上下文句柄和相關的句柄

一個服務上下文句柄定義了決定OCI調用的上下文的屬性。服務上下午句柄包含3個句

柄作為它的屬性,分别代表一個伺服器連接配接、一個使用者會話和一個事務。圖2-3列出了這些屬性

         圖 2-3

         ·一個伺服器句柄Server Handle識别對一個資料庫的連接配接。

         ·一個使用者會話句柄User Session Handle定義了一個使用者的角色和權限以及函數執行的操作上下文。

    ·一個事務句柄定義了SQL操作所屬的事務。

    在需要更複雜的會話管理的應用程式中,服務上下午句柄必須被顯式地配置設定,并且伺服器句柄和使用者會話句柄必須通過OCIAttrSet()函數被顯式地設定到服務上下午句柄中。OCIServerAttach()函數和OCISessionBegin()函數分别初始化伺服器和使用者會話句柄。

    當應用程式對資料庫做修改時,OCI自動隐式配置設定的事務句柄正确地工作。

2.3.4          語句句柄、綁定句柄和定義句柄

一個語句句柄是識别SQL或者PL/SQL語句以及與之相連的屬性的上下文,如圖2-4所

         圖2-4

         關于輸入綁定變量和輸出綁定變量的資訊儲存于綁定句柄中bind handle。OCI庫為每一個與OCIBindByName()函數或者OCIBindByPos()函數相連的占位符配置設定一個綁定句柄。使用者一定不可以配置設定綁定句柄。它們是由綁定函數隐式配置設定的。

         查詢傳回的資料根據定義句柄(define handle)的描述來轉換和擷取。OCI庫為每一個OCIDefineByPos()函數中所定義的輸出變量配置設定一個定義句柄。使用者一定不可以配置設定定義句柄。它們是由定義函數隐式配置設定的。

         綁定句柄和定義句柄是由OCI庫顯式配置設定的,并且如果綁定或者定義操作是重複的話,綁定句柄和定義句柄是被重複使用的。當語句句柄被釋放或者當一個新的語句被準備到語句句柄上後,綁定句柄或者定義句柄就被釋放。顯式配置設定綁定或者定義句柄可能導緻記憶體洩露。顯式釋放綁定句柄或者定義句柄可能導緻程式異常終止。

2.3.5          描述句柄

描述句柄describe handle由OCI描述函數所使用,OCIDescribeAny()。這個函數擷取關于

資料庫中的資料庫對象的資訊(例如,函數或者過程)。這個函數有一個參數是描述句柄,以及關于被描述的對象的附加資訊。當函數執行完成後,描述句柄就存有關于那個對象的資訊。然後OCI應用程式可以通過參數描述符的屬性擷取描述資訊。

2.3.6          句柄屬性

所有的OCI句柄都有表示存儲在那個句柄中的資料的屬性。我們可以通過屬性擷取函

數OCIAttrGet()來擷取句柄屬性值,并且我們可以通過OCIAttrSet()函數來設定句柄的屬性值。

         例如,下面的代碼顯示了通過寫入會話句柄的OCI_ATTR_USERNAME屬性來設定會話句柄中的使用者名。

         text username[] = “hr”;

         err = OCIAttrSet((dvoid*)mysessp,          OCI_HTYPE_SESSION,      (dvoid*)username,

                            (ub4)strlen((char*)username),        OCI_ATTR_USERNAME,  (OCIError*)myerrhp);

         一些OCI函數要求在這些函數被調用前,一些特定的句柄屬性值被設定。例如,調用OCISessionBegin()函數來設定使用者的登入會話,在這個函數被調用之前,必須設定使用者會話句柄的使用者名和密碼屬性。

         其他的OCI函數執行完成後,會在句柄屬性中提供有用的傳回資料。例如,當OCIStmtExecute()函數被調用來執行SQL查詢時,關于所選字段的描述資訊被傳回到語句句柄中。

         ub4  parmcnt;

         Err = OCIAttrGet((dvoid*)stmhp,    (ub4)OCI_HTYPE_STMT,           (dvoid*)&parmcnt,  (ub4)0,

                                               (ub4)OCI_ATTR_PARM_COUNT,            errhp);

2.3.7          OCI描述符

OCI描述符descriptor和定位符locator是維護特殊資料資訊的不透明資料結構。表2-2

列出了它們以及對應的C資料結構和還有在OCIDescriptorAlloc()函數中所用到的OCI類型常量。OCIDescriptorFree()函數釋放描述符和定位符。

表2-2

下面描述了各種描述符類型的主要目的。

·OCISnapshot—用于語句執行

·OCILobLocator—用于LOB(OCI_DTYPE_LOB)或者BFILE(OCI_DTYPE_FILE)函數

·OCIParam—用于描述函數

·OCIRowid—用于綁定或者定義ROWID值

2.3.7.1   LOB和BFILE 定位符

一個大對象(LOB)是儲存二進制大資料或者字元大對象(CLOB)數

據的Oracle資料類型。在資料庫中,一個不透明的叫做LOB定位符的資料結構儲存在一個資料庫行的LOB字段中。定位符作為實際LOB值的指針,實際的LOB值儲存在其他的地方。

    OCI LOB定位符用于對LOB(BLOB或者CLOB)類型或者FILE(BFILE)類型進行OCI操作。OCILobXXX函數使用LOB定位符作為參數而不是LOB數值。OCI LOB函數不使用實際的LOB資料作為參數。它們使用LOB定位符作為參數并且通過引用它們來操作LOB資料。

    通過向OCIDescriptorAlloc()函數傳遞OCI_DTYPE_LOB作為類型參數來為BLOBs或者CLOBs配置設定LOB定位符,傳遞OCI_DTYPE_FILE作為類型參數為BFILEs配置設定LOB定位符。

    注意:這兩種LOB定位符類型是不能互換的。當綁定或者定義一個BLOB或者CLOB時,應用程式必須注意定位符是否是通過OCI_DTYPE_LOB配置設定的。同樣,當綁定或者定義一個BFILE時,應用程式必須確定使用OCI_DTYPE_FILE配置設定定位符。

    一個OCI應用程式可以使用一個包含有LOB字段或者屬性的SQL語句從Oracle資料庫擷取LOB定位符。這種情況下,應用程式需要首先配置設定LBO定位符然後用它來定義一個輸出變量。與此類似,一個LOB定位符可以被用來作為綁定操作的一部分以建立一個LOB和一個SQL語句中的占位符的聯結。

2.3.7.2   參數描述符

OCI應用程式使用參數描述符擷取關于所選字段或者資料庫對象的資訊。通過描述操

作擷取這種資訊。

    參數描述符是唯一的不通過OCIDescriptorAlloc()函數配置設定的描述符。我們隻有通過描述句柄、語句句柄或者複雜對象擷取句柄來擷取它,使用OCIParamGet()函數。

3.     OCI程式設計步驟

下面描述開發一個OCI應用程式的細節。

3.1    OCI環境初始化

  這部分描述如何初始化OCI環境,設立一個伺服器的連接配接,并且授權一個使用者對資料庫

執行操作。

  首先,初始化OCI環境時有三個主要步驟:

    ·建立OCI環境

    ·配置設定句柄和描述符

·應用程式初始化、連接配接和建立會話

    3.1.1建立OCI環境

  每一個OCI函數調用都是在OCIEnvCreate()函數所建立的環境中執行的。這個函數必

須在其他OCI函數執行前被調用。唯一的例外是設定OCI共享模式的程序級屬性。

    OCIEnvCreate()函數的模式(mode)參數指定應用程式是否能夠:

         ·運作在多線程環境中(mode=OCI_THREADED).

    ·使用對象(mode=OCI_OBJECT).Usethe AQ subscription registration

    程式也可以選擇不使用這些模式而使用預設模式(mode=OCI_DEFAULT)或者它們的聯合,使用垂直條(|)将它們分開。例如,如果mode=(OCI_THREADED|OCI_OBJECT),然後應用程式運作在多線程環境中并且使用對象。

    我們可以為每個OCI環境指明使用者定義的記憶體管理函數。

    3.1.2 配置設定句柄和描述符

    Oracle資料庫提供了用于配置設定和釋放句柄及描述符的OCI函數。在向OCI函數傳遞句柄之前我們必須使用OCIHandleAlloc()函數配置設定句柄,除非OCI函數,比如OCIBindByPos(),自動為我們配置設定句柄。

    我們使用OCIHandleAlloc()函數來配置設定表2-1列出的句柄。

    3.1.3 應用程式初始化、連接配接和建立會話

    一個應用程式必須調用OCIEnvCreate()函數來初始化OCI環境句柄。

    沿着這一步,應用程式有兩個選項來設定一個伺服器連接配接和開始一個使用者會話:單使用者、單連接配接或者多會話多連接配接。

    注意:應該使用OCIEnvCreate()函數而不是OCIInitialize()函數和OCIEnvInit()函數。OCIInitialize()和OCIEnvInit()函數是向後相容的函數。

    3.1.3.1 單使用者、單連接配接

    如果應用程式在任何時刻僅為各個資料庫連接配接維持一個單使用者會話,這個選項就是簡化的登入函數。

    當一個應用程式調用OCILogon()函數時,OCI庫初始化傳遞給它的服務上下午句柄,并且建立一個到使用者指定的資料庫的連接配接。

    下面的例子顯示了OCILogon()函數的用法:

    OCILogon(envhp,  errhp, &svchp,  (text*) “hr”,  nameLen, (text*) “hr”,

                passwdLen,  (text*) “oracledb”,  dbnameLen);

    這個函數的參數包括服務上下午句柄(它将被初始化),使用者名,使用者的密碼,還有用來設定連接配接的資料庫名。這個函數會隐式地配置設定伺服器句柄和使用者會話句柄。

    如果應用程式使用這個登入函數,則服務上下文句柄、伺服器句柄和使用者會話句柄将成為隻讀的。應用程式不能通過改變服務上下午句柄的相關屬性來轉換會話或事務。

    使用OCILogon()函數初始化它的會話和認證的應用程式必須調用OCILogoff()函數來終止它們。

3.1.3.2 多會話或者多連接配接

    這個選項使用顯式的伺服器連接配接和開始會話函數來維持一個資料庫連接配接之上的多使用者會話和連接配接。伺服器連接配接和開始會話的函數分别是:

    ·OCIServerAttach()—建立一個到資料源執行OCI操作的通路路徑。

    ·OCISessionBegin()—為一個使用者設定一個針對某一特定伺服器的會話。為了在資料庫伺服器上執行資料庫操作,必須執行這個函數。

    這兩個函數設定一個能夠使我們執行SQL或者PL/SQL語句的執行環境。

3.1.4在OCI中處理SQL語句

在OCI中處理SQL語句的細節在後面描述。

3.2    送出或者復原事務

應用程式通過調用OCITransCommit()函數來送出對資料庫的修改。這個函數使用一

個服務上下文句柄作為它的一個參數。與此服務上下文句柄相連的事務将被送出。應用程式可以顯式地建立事務或者當應用程式修改資料庫時隐式地建立事務。

注意:如果使用OCIExecute()函數的OCI_COMMIT_ON_SUCCESS模式,應用程式可以在每個語句執行後選擇性地送出事務,這樣可以節省一個額外的網絡開銷。

使用OCITransRollback()函數來復原事務。

如果一個應用程式以非正常方式同Oracle斷開連接配接,比如網絡連接配接斷開,并且OCITransCommit()函數沒有被調用,則所有活動的事務都會被自動復原。

3.3    終止應用程式

一個OCI程式需要在它終止前執行如下步驟:

1.       調用OCISessionEnd()函數删除每一個會話的使用者會話。

2.       調用OCIServerDetach()函數删除每一個資料源的通路。

3.       調用OCIHandleFree()函數來釋放每一個句柄。

4.       删除環境句柄,環境句柄會釋放所有與之相連的句柄。

注意:當一個父句柄被釋放後,任何與其相連的句柄都會被自動釋放。

對OCIServerDetach()函數和OCISessionEnd()函數的調用不是必須的,但是建議進行調用。

如果應用程式終止并且沒有調用OCITransCommit()函數沒有被調用,則任何之前的事務都會被自動復原。

3.4    OCI中的錯誤處理

OCI函數有一個傳回代碼集合,表2-3列出了OCI傳回代碼,這些傳回代碼指出了函數

的成功或者失敗,比如OCI_SUCCESS或者OCI_ERROR,或者應用程式需要的其他資訊,比如OCI_NEED_DATA或者OCI_STILL_EXECUTING。大多數OCI函數會傳回這些傳回代碼中的一個。

         表2-3 OCI傳回代碼

         如果傳回代碼提示發生了一個錯誤,應用程式可以調用OCIErrorGet()函數來擷取Oracle的錯誤代碼和資訊。OCIErrorGet()函數的一個參數是引起錯誤的錯誤句柄。

         資料的傳回代碼和錯誤代碼

         表2-4列出了當資料擷取時正常、為空或者被截短時的OCI傳回代碼。錯誤号碼、訓示器變量和字段傳回代碼。

         表2-4 傳回和錯我代碼

3.5    編碼建議 Coding Guidelines

  這部分描述編寫OCI應用程式時,一些附加的問題。

3.5.1         參數類型 Parameter Types

OCI函數使用很多不同類型的參數,包括整數、句柄和字元串。

位址參數Address Parameters

位址參數用來将變量的位址傳遞至Oracle伺服器。

整型參數Integer Parameters

二進制整數和短的二進制整型參數的大小依賴于系統。

         字元串參數Character String Parameters

         字元串參數是一種特殊類型的位址參數。每個需要一個字元串參數的OCI函數都需要一個字元串長度參數。

         設定一個字段值為空Inserting Nulls into a Column

         我們可以有多種方式向一個資料庫字段中插入空值。

1.  在INSERT或者UPDATE語句中使用NULL。例如,下面的SQL語句

INSERT  INTO  emp   (ename, empno,  deptno)

                   VALUES    (NULL,  8010,   20)

會使ENAME字段為NULL。

2.  在OCI綁定函數中使用訓示器變量。

3.5.2          訓示器變量 Indicator Variables

每一個定義和綁定OCI函數都有一個參數與一個訓示器變量相連或者一個訓示器變量數

組相連。

         C語言沒有NULL值的概念,是以我們将一個輸入變量input variable聯系到訓示器變量indicator variable來指明占位符place holder是否為NULL值。當資料傳到Oracle時,這些訓示器變量的值決定一個資料庫字段是否被設為空值。

         對于輸出變量output variable,訓示器變量訓示Oracle傳回的值是否為NULL或者被截短。在OCIStmtFetch()函數擷取到NULL或者OCIStmtExecute()函數執行時出現truncation時,OCI函數傳回OCI_SUCCESS。輸出訓示器變量被指派。

         訓示器變量的類型是sb2。在訓示器變量數組中,單獨的訓示器元素為sb2類型。

3.5.2.1    輸入Input

對于輸入宿主變量,OCI應用程式可以像訓示器變量賦予如下值:

表3-5 輸入訓示器變量值 Input Indicator Values

         當訓示器變量值為-1時,Oracle忽略輸入變量的值,将字段值設定為NULL。

         當訓示器變量值大于等于0時,Oracle将訓示器變量的值賦給字段。

3.5.2.2    輸出Output

輸出時,Oracle可以賦予訓示器變量如下值:

           表3-6 輸出訓示器變量值 Output  Indicator Values

         訓示器變量值為-2時,字段值的長度大于輸出變量的長度;字段值被截短。另外,字段值的原始長度大于sb2類型的訓示器變量所能儲存的最大數值。

         訓示器變量值為-1時,所選字段的值為NULL,并且輸出變量的值不變。

         訓示器變量值為0時,Oracle将完整的字段值賦給了宿主變量。

         訓示器變量值大于0時,字段值的長度大于輸出變量的長度,字段被截短。訓示器變量中傳回的正數是字段值被截短前的真實長度。

3.6   

4       資料類型

這部分介紹OCI應用程式中使用的Oracle外部資料類型的參考。也讨論Oracle資料類型

以及當我們的應用程式和Oracle傳遞資料時繁盛的内部資料類型和外部資料類型之間的轉換。

4.1   Oracle資料類型

一個OCI程式的主要目的之一就是同一個Oracle伺服器通信。OCI應用程式可以通過SQL

SELECT查詢從資料庫表中擷取資料,或者通過INSERT、UPDATE、或者DELETE語句修改表中的資料。

         在資料庫内部,值儲存在表的字段中。在内部,Oracle通過特定格式的内部資料類型internal datatypes來表示資料。内部資料類型包括NUMBER、CHAR和DATE。

         通常,OCI應用程式不與資料的内部資料類型工作,而是與宿主主演預先定義的資料類型工作。當資料在OCI應用程式和資料庫表中傳遞時,OCI庫在内部資料類型和外部資料類型之間進行轉換。

         外部資料類型external datatypes是宿主語言在OCI頭檔案中定義的資料類型。當一個OCI應用程式綁定輸入變量時,綁定參數中有一個參數用來說明變量的外部資料類型代碼(SQLT代碼)。同樣地,當定義調用中指明輸出變量時,必須說明擷取到的資料的外部表示。

         OCI可以進行大範圍的Oracle和OCI應用程式間的資料類型轉換。OCI外部資料類型多于Oracle内部資料類型。

  4.1.1 使用外部資料類型代碼External Datatype Codes

         外部資料類型代碼告知Oracle我們應用程式中的宿主變量被如何表示。這決定了當資料被傳回到輸出變量時,如何進行轉換或者輸入變量的資料如何轉換成Oracle的字段值。例如,如果我們想要将一個Oracle字段中的NUMBER轉換成變長字元數組,我們需要在OCIDefineByPos()函數中指定VARCHAR2外部資料類型代碼。

         為轉換綁定變量到一個Oracle字段值,需要指明對應于綁定變量的外部資料類型代碼。例如,如果我們想要輸入一個字元串比如 02-FEB-65到一個DATE字段,将資料類型指定為字元串并且将長度參數設定為9.

4.2   内部資料類型

表4-1列出了Oracle的内部資料類型,以及各個類型的最大内部長度和類型代碼。

         表4-1 Oracle内部資料類型

4.3   外部資料類型

表4-2列出了外部資料類型的類型代碼。為每一種資料類型,表中都列出了Oracle的内

部資料被正常轉換為的C語言中的程式變量類型。

         表4-2 外部資料類型和代碼

4.3.1 VARCHAR2

         VARCHAR2資料類型是一個變長字元串,其最大長度為4000位元組。

         輸入Input

         OCIBindByName()函數或者OCIBindByPos()函數中的value_sz參數決定了可變長字元串的長度。

         如果value_sz參數大于0,Oracle從程式中的緩沖區位址開始讀取其所指定的位元組數。如果value_sz參數為0,Oracle将綁定變量看做NULL,不考慮其真實内容。如果我們向一個具有NOT NULL限制的字段插入NULL值,Oracle會報錯,并且改行不會被插入。

         輸出Output

         在OCIDefineByPos()函數的value_sz參數中指定想要擷取的傳回值的長度。如果value_sz為0,則沒有資料被傳回。

         為檢測傳回值是否為空或者字元截短是否發生,就要在OCIDefineByPos()函數中使用訓示器變量參數。如果我們沒有指定訓示器變量參數并且傳回一個空值,擷取函數會傳回錯誤代碼OCI_SUCCESS_WITH_INFO。

4.3.2 STRING

NULL結尾的String格式類似于VARCHAR2格式,除了string格式會包含一個NULL終止

符。這個資料類型對C語言非常有用。

         輸入Input

         如果NULL終止符沒有在指定的長度中發現,Oracle會産生如下錯誤

         ORA-01480: trailing  NULL missing from STR bind value

         如果沒有指定長度,則OCI使用隐含的最大長度—4000.

         輸出Output

         在被傳回的最後一個字元後面添加一個NULL終止符。如果字元串超出了指定的字段長度,則其會被截短并且輸出變量的最後一個字元包含NULL終止符。

4.3.3 DATE

         Date以二進制格式儲存,包含7個位元組,如表4-3所示。

         表4-3 Data資料類型的格式

4.3.4 LOB 定位符 Locator

       當一個OCI應用程式發出的SQL查詢中包括一個LOB字段時,查詢傳回的是LOB定位符,而不是實際的LOB字段值。在OCI中,LOB定位符映射OCILobLocator類型的變量。

       OCI中的LOB相關函數使用一個LOB定位符作為它們的參數。這些OCI函數假定LOB定位符已經被建立,不論其指向的LOB是否含有資料。

         綁定操作和定義操作都是對LOB定位符進行操作,通過OCIDescriptorAlloc()函數來配置設定LOB定位符。

         綁定和定義LOB的資料類型代碼如下:

         ·SQLT_BLOB—一個二進制LOB資料類型。

    ·SQLT_CLOB—一個字元型LOB資料類型。

5       在OCI程式中使用SQL語句

這一節讨論使用OCI處理SQL語句是所涉及的概念和步驟。

5.1   SQL語句處理概要

一個OCI程式的通常任務就是接受和處理SQL語句。這部分概述一下SQL進行中所涉及

的步驟。

         一旦我們配置設定了必要的句柄并且連接配接至伺服器,按照圖5-1中的步驟來處理SQL語句。

         圖5-1 處理SQL語句的步驟

1.       準備語句。使用OCIStmtPrepare()函數或者OCIStmtPrepare2()函數來定義一個應用程式請求。

2.       如果有必要的話,需要綁定占位符。對于DML語句和有輸入變量的查詢,要執行使用以下的函數執行一個或者多個綁定。

·OCIBindByPos()

·OCIBindByName()

·OCIBindObject()

·OCIBindDynamic()

·OCIBindArrayOfStruct()

3.       也可以使用OCIStmtPrepare2()函數來準備一個語句進行執行。OCIStmtPrepare2()函數是OCIStmtPrepare()函數的增強版,其引入了對語句緩存的支援。

4.       執行。調用OCIStmtExecute()函數來執行語句。對于DDL語句則不需要其他步驟。

5.       如有必要,需要進行描述。如有必要使用OCIParamGet()函數和OCIAttrGet()函數來描述所選字段。這是一個可選步驟。

6.       如有必要,需要進行定義。對于查詢,執行一個或者多個OCIDefineByPos()、OCIDefineObject()、OCIDefineDynamic()或者OCIDefineArrayOfStruct()函數來為SQL語句中的各個所選字段定義輸出變量。

7.       如有必要,需要進行擷取操作。對于查詢,調用OCIStmtFetch()來擷取查詢的結果。

按照這些步驟,應用程式可以釋放已經配置設定的句柄,然後斷開同伺服器的連接配接,或者處

理另外的SQL語句。

5.2   準備語句

通過使用語句準備函數和任何必要的綁定函數,SQL和PL/SQL語句為執行做好準備。

應用程式指明一個SQL或者PL/SQL語句并且将語句中的占位符綁定至執行是所用的資料。用戶端庫為準備的語句配置設定空間。

         一個應用程式調用OCIStmtPrepare()函數來請求一個SQL或者PL/SQL語句為執行做準備并且向其傳遞一個之前配置設定的語句句柄。這是一個本地調用,不需要同伺服器的通訊。此時,在語句和特定的伺服器間沒有聯結。

         在OCI中綁定占位符

       大多數DML語句,以及一些查詢(比如那些帶有Where子句的),需要程式将SQL或者PL/SQL中的一部分資料傳遞給Oracle。這個資料可以使常量或者字元串,在我們的程式編譯時已經是已知的。例如,下面的項資料庫中增加一條員工記錄的SQL語句:

         INSERT INTO  emp   VALUE

                   (2365,   ‘BESTRY’,  ‘PROGRAMER’,   2000,   20)

5.3   執行語句

一個OCI應用程式通過調用OCIStmtExecute()函數來執行已經準備好的語句。

     當一個OCI應用程式執行查詢時,它從資料庫中擷取那些符合查詢條件的資料。在資料

庫内部,資料以Oracle定義的格式儲存。當結果傳回後,OCI應用程式可以請求将資料轉換成一種特定的宿主語言格式,并将其儲存在一個特定的輸出變量或者緩沖區中。

         對于查詢中的所選字段中的每一個字段,OCI程式都必須定義一個接收查詢到的結果的輸出變量。定義步驟說明了緩沖區的位址和将要擷取到的資料的類型。

         注意:如果一個SELECT語句的輸出變量在調用OCIStmtExecute()函數前進行了定義,OCIStmtExecute()函數中的iters參數指明的行數将會直接擷取到已經定義的輸出緩沖區中,并且等于預擷取行數的其他行會被預擷取到。如果沒有其他行,則不需要調用OCIStmtFetch()就可以完成擷取操作。

5.4   擷取查詢結果

如果一個OCI應用程式已經處理了一個查詢。通常會在語句執行完成後調用

OCIStmtFetch()函數或者OCIStmtFetch2()函數來擷取查詢結果。Oracle鼓勵使用支援可滾動遊标scrollable cursors的OCIStmtFetch2()函數。

         擷取到的資料被放置到已經在定義操作中指明的輸出變量中。

6       綁定和定義操作

6.1   OCI中的綁定概述

本小節擴充綁定和定義的基本概念,并且提供我們在OCI應用程式中可以使用的綁定和

定義操作的更詳細的資訊。另外,本節将讨論結構體數組的使用,以及其他的設計綁定、定義和字元轉換的議題。

         例如,如下INSERT語句

         INSERT INTO  emp   VALUES

                            (:empno,   :ename,   :job,    :sal,   :deptno)

         還有如下變量聲明

         text   *ename,   *job;

         sword       empno,   sal,  deptno;

         綁定步驟再占位符名字和程式變量之間建立結合。綁定也說明了程式變量的資料類型和長度,如圖6-1所示

         圖6-1 使用OCIBindByName()函數來結合占位符和程式變量

         如果我們隻改變綁定變量的值,則沒有必要為了重新執行語句而進行重新綁定。因為綁定是按引用綁定,隻要變量位址和句柄位址保持不變,我們就可以重新執行引用那個變量的語句而不需進行重新綁定。

         6.1.1 按名字綁定和按位置綁定

         上述例子是一個按名字綁定的例子。語句中的每個占位符都有一個名字與其相結合,比如’ename’或者’sal’。當這個語句已經準備好并且占位符已經和應用程式中的一個變量值相結合時,結合是通過OCIBindByName()函數設立的。

         第二種綁定是按位置進行綁定。在按位置綁定中,通過占位符在語句中的位置而不是名字來進行綁定。為了進行綁定,使用OCIBindByPos()函數對輸入值和占位符的位置建立結合。

         使用之前的例子進行按位置綁定:

         INSERT  INTO   emp   VALUES

                   (:empno,    :ename,   :job,    :sal,    :deptno)

         這5個占位符分别通過調用OCIBindByPos()函數進行綁定,并且将占位符在語句中的位置傳遞到OCIBindByPos()函數的位置position參數中。例如,調用OCIBindByPos()函數并傳遞位置參數1,:empno占位符将會被綁定,:ename則傳遞位置參數2。

         在重複綁定的情況下,僅有一個單獨綁定調用是必要的。考慮如下的SQL語句,這個語句查詢資料庫中提成和收入均大于某一數量的員工。

         SELECT empno   FROM   emp

                   WHERE  sal  >   :some_value

                   AND          comm  >  :some_value

         通過調用一次OCIBindByName()函數進行按名字綁定,OCI程式就可以完成該語句的綁定操作。在這種情況下,第二個占位符繼承第一個占位符的綁定資訊。

         6.1.2 OCI綁定的步驟

         綁定占位符需要多個步驟。下面的例子顯示了綁定一個SQL語句中的各個占位符的句柄配置設定和綁定。

         text* insert  = (text*) “INSERT  INTO emp  (empno,  ename, job,  sal,  deptno) \

                   VALUES  (:empno,  :ename,   :job,   :sal, :deptno)”;

         . . .

         checker(errhp,   OCIBindByName(  stmthp,   &bnd1p,   errhp,   (text *) ":ENAME",

strlen(":ENAME"),   ( ub1 *) ename,   enamelen+1,    SOLT_STR,   (dvoid *) 0,

(ub2 *) 0,     (ub2) 0,     (ub4) 0,      (ub4 *) 0,     OCI_DEFAULT));

         checkerr(errhp,       OCIBindByName(  stmthp,  &bnd2p,    errhp,        (text *) ":JOB",

strlen(":JOB"),     (ub1*) job,    joblen+1,    SQLT_STR,  (dvoid *)&job_ind, (ub2 *) 0,              (ub2) 0,    (ub4) 0,     (ub4 *) 0,        OCI_DEFAULT));

checkerr(errhp,       OCIBindByName(  stmthp,   &bnd3p,    errhp,     (text*) ":SAL",

strlen(":SAL"),         (ub1 *) &sal,    (sword) sizeof(sal),      SQLT_INT,

(dvoid *) &sal_ind,   (ub2 *) 0,  (ub2) 0,    (ub4)0,    (ub4 *) 0,

OCI_DEFAULT));

checkerr(errhp,       OCIBindByName(  stmthp,   &bnd4p,   errhp,  (text *) ":DEPTNO",

strlen(":DEPTNO"),         (ub1 *) &deptno,     (sword)sizeof(deptno),           SQLT_INT,

(dvoid *) 0,      (ub2*) 0,         (ub2) 0,   (ub4) 0,   (ub4*) 0,           OCI_DEFAULT));

checkerr(errhp,       OCIBindByName(     stmthp,  &bnd5p,         errhp, (     text *) ":EMPNO",

strlen(":EMPNO"),                    (ub1 *) &empno,    (sword) sizeof(empno),           SQLT_INT,

(dvoid *) 0,      (ub2*) 0,         (ub2) 0,   (ub4) 0,   (ub4*) 0,          OCI_DEFAULT));

6.1.3  OCI綁定LOBs

         有兩種方式來綁定LOBs。

         ·綁定LOB定位符locator,而不是實際的LOB值。在這種情況下,LOB數值是通過向OCILOB函數傳遞LOB定位符完成的。

    ·直接綁定LOB數值,而不是使用LOB定位符。

    綁定LOB定位符

    一個單獨的定位符或者一個定位符數組都可以在一個單獨的綁定調用中綁定。在這兩種情況下,應用程式必須傳遞LOB定位符的位址而不是定位符本身。例如,如果一個應用程式已經準備了一個SQL語句。

    INSERT  INTO  some_table  VALUES  (:one_lob)

    one_lob是一個與LOB字段對應的綁定變量,并且已經做出了如下聲明:

    OCILobLocator *one_lob;

    然後,下面的調用将會被用來綁定占位符和執行語句。

    One_lob  = OCIDescriptorAlloc(…OCI_DTYPE_LOB…);

    . . .

    OCIBindByName(…(dvoid*)&one_lob,. . .SQLT_CLOB, . . .);

    OCIStmtExecute(…, 1, …); 

    在描述符可以使用之前,我們必須調用OCIDescriptorAlloc()函數來配置設定描述符。

6.2   OCI定義概述

查詢語句将從資料庫中擷取的資料傳回到我們的應用程式中。當處理一個查詢的時候,

我們必須為所選字段中的每一個字段定義一個輸出變量。定義步驟決定了傳回值儲存在什麼地方和以什麼形式儲存。

         例如,如果我們的應用程式處理如下語句,我們需要定義兩個輸出變量,一個用來接收ename字段傳回的值,一個用來接收ssn字段傳回的數值。

         SELECT  name,    ssn   FROM  employess

                   WHERE  empno =   :empnum

         如果我們隻對擷取name字段值感興趣,則我們可以不為ssn字段定義輸出變量。

         OCI在用戶端本地處理定義調用。除了說明儲存結果的緩沖區的位置,定義步驟還決定了當資料傳回到應用程式時如何進行資料轉換。

         OCIDefineByPos()函數的dty參數說明輸出變量的資料類型。當資料擷取至輸出變量時,OCI能夠執行大範圍的資料轉換。例如,Oracle的DATE類型的内部資料可以自動轉換為String資料類型。

6.2.1         OCI定義的步驟

通過調用OCIDefineByPos()函數來完成基本的定義。這一步建立了所選字段和輸出變量

的結合。

         下面的例子顯示了在執行完成後一個輸出變量被定義。

         SELECT department_name  FROM  departments  WHERE  department_id = :dept_input

         Printf(“Enter  employee dept:”);

         Scanf(“%d”,  &deptno);

         if (  (status =OCIStmtExecute(svchp,  stmthp,  errhp,  0,  0,  (OCISnapshot *) 0,

(OCISnapshot *) 0,   OCI_DEFAULT))   &&  (status != OCI_NO_DATA))

{

checkerr(errhp, status);

return   OCI_ERROR;

}

if (status == OCI_NO_DATA) {

printf("The dept you entered doesn'texist.\n");

return    0;

}

checkerr(errhp,   OCIParamGet((dvoid*)stmthp,   (ub4) OCI_HTYPE_STMT,   errhp,

(dvoid **)&parmdp,   (ub4) 1));

checkerr(errhp,   OCIAttrGet((dvoid*)parmdp,    (ub4) OCI_DTYPE_PARAM,

(dvoid*) &deptlen,    (ub4 *)&sizelen,    (ub4)OCI_ATTR_DATA_SIZE,

(OCIError *) errhp ));

dept = (text *) malloc(  (int)deptlen + 1  );

if (status = OCIDefineByPos(stmthp,   &defnp,    errhp,  1,   (dvoid *) dept,

(sb4) deptlen+1,  SQLT_STR,   (dvoid *) 0,  (ub2 *) 0,  (ub2 *) 0,  OCI_DEFAULT))

{

checkerr(errhp, status);

return OCI_ERROR;

}

6.2.2         OCI定義LOB輸出變量

有兩種方式定義LOBs:

·定義一個LOB定位符,而不是真實的LOB數值。這種情況下,OCI LOB函數通過LOB

定位符來讀取或者寫入LOB數值。

    ·不使用LOB定位符,直接定義一個LOB值。

         定義LOB定位符

         應用程式必須傳遞LOB定位符的位址而不是定位符本身。例如,如果應用程式已經準備了下面的SQL語句。

         SELECT  lob1   FROM   some_table;

         其中lob1是LOB字段并且one_lob是對應于LOB字段的定義變量。其聲明如下:

         OCILobLocator*   one_lob;

         下面的步驟綁定占位符,并執行語句。

         One_lob   =  OCIDescriptorAlloc(…OCI_DTYPE_LOB…);

         …

         OCIDefineByPos(...1,  …, (dvoid*) &one_lob,  …SQLT_CLOB,. . .);

         OCIStmtExecute(…, 1, …);      

         在描述符可以使用之前,我們必須調用OCIDescriptorAlloc()函數來配置設定描述符。

6.2.3         

6.3   

7       OCI相關函數

這一節介紹Oracle的OCI相關函數。

7.1   連接配接、認證和初始化函數

這一小節描述OCI的連接配接connect、授權authorize和初始化initialize函數。表7-1列出了

這些函數

表7-1 連接配接、授權和初始化函數

7.1.1 OCIEnvCreate()函數

作用:為執行OCI函數的執行建立和初始化一個環境。

原型:

     Sword  OCIEnvCreate(                  OCIEnv                                **envhp,

                                                             Ub4                                      mode,

                                                             CONST   dvoid                 *ctxp,

                                                             CONST   dvoid                 *(*malocfp)

                                                                                                           (dvoid*ctxp,

Size_t  size),

                                                                 CONST     dvoid                 *(*ralocfp)

                                                                                                                (dvoid*ctxp,

                                                                                                                 dvoid* memptr,

                                                                                                                size_t  newsize),

                                                                 CONST     void                   (*mfreefp)

                                                                                                                (dvoid*ctxp,

                                                                                                                 dvoid *memptr),

                                                                 size_t                                   xtramem_sz,

                                                                 dvoid                                   **usrmempp);

參數:

         envhpp: 指向環境句柄的指針。

         mode: 指明初始化的模式。有效的模式有:

         ·OCI_DEFAULT—預設值,其為非UTF-16編碼。

    ·OCI_THREADED—使用線程環境。

    ·OCI_OBJECT—使用對象特性。

    ·OCI_EVENT—利用出版-訂閱特性。

    ·OCI_NO_UCB—禁止調用動态回調函數OCIEnvCallback。當環境建立時,預設允許調用OCIEnvCallback函數。

    ·OCI_ENV_NO_MUTEX—在此模式中沒有互斥。所有的在環境句柄中完成,或者環境句柄派生的句柄上完成的OCI調用都必須被序列化。

    ·OCI_NEW_LENGTH_SEMANTICS—

    ctxp: 指明使用者為記憶體回調函數定義的上下文。

    malocfp:指明使用者定義的記憶體配置設定函數。如果為OCI_THREADED模式,這個記憶體配置設定函數必須是支援多線程安全通路的。

    ctxp:指明使用者定義的記憶體配置設定函數的上下文指針。

    size:指明被使用者定義的記憶體配置設定函數配置設定的記憶體大小。

    ralocfp:指明使用者定義的記憶體再配置設定函數。如果為OCI_THREADED模式,這個記憶體配置設定函數必須是支援多線程安全通路的。

    ctxp:使用者定義的記憶體再配置設定函數的上下文指針。

    memp:記憶體塊的指針。

    newsize:被配置設定的記憶體的新大小。

    mfreefp:說明使用者定義的記憶體釋放函數。如果為OCI_THREADED模式,這個記憶體釋放函數必須是支援多線程安全通路的。

    ctxp:使用者定義的記憶體釋放函數的上下文指針。

    memptr:被釋放的記憶體的指針。

    xtramemsz:說明使用者配置設定的記憶體的數量。

    usrmempp:為使用者傳回xtramemsz大小的記憶體的指針。

注釋:

    這個函數為在使用者指定模式下的所有的OCI函數調用建立一個環境。

    這個函數傳回一個環境句柄,這個環境句柄被其他的OCI函數使用。在OCI中可以有多個環境,各有其環境模式。這個函數含執行各種模式所需要的程序級初始化。

7.1.2         OCIServerAttach函數

作用:為OCI操作建立一個對資料源通路路徑。

原型:

         Sword      OCIServerAttach(   OCIServer                  *srvhp,

                                                                 OCIError                    *errhp,

                                                                 CONSTtext               *dblink,

                                                                 Sb4                              dblink_len,

                                                                 Ub4                             mode);

參數:

srvhp:一個未被初始化的伺服器句柄,這個伺服器句柄被這個函數初始化。傳遞一

個已經被初始化的句柄會産生錯誤。

errhp:錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         dblink:說明使用的資料庫伺服器。這個參數指向一個字元串,這個字元串說明了連接配接字元串。如果連接配接字元串為NULL,則這個函數調用會連至預設主機。

         dblink_len:其為dblink所指向的字元串的長度。

         mode:說明操作模式。有效的模式有:

         ·OCI_DEFAULT:為預設模式。

         ·OCI_CPOOL:使用連接配接池。

注釋:

         這個函數用來建立一個OCI應用程式和一個特定伺服器之間的連接配接。

         這個函數初始化伺服器句柄,這個伺服器句柄必須是已經被OCIHandleAlloc()函數配置設定的。通過調用OCIAttrSet()函數可以講這個函數初始化的伺服器上下文句柄連接配接到一個服務上下午句柄。一個設立了這個連接配接,就可以對伺服器執行OCI操作。

         如果一個應用程式對多個伺服器執行操作,則可以維持多個伺服器上下文句柄。可以對服務上下文句柄目前綁定的任何一個伺服器上下文句柄進行OCI操作。

         當OCIServerAttach()函數成功執行後,會啟動一個Oracle隐蔽程序shadow process。為清除這個Oracle隐蔽程式,必須調用OCISessionEnd()函數和OCIServerDetach()函數。否則,随着隐蔽程序的累積會引起Unix系統耗盡程序。如果資料庫重新開機并且沒有足夠的程序,資料庫就無法啟動。

例子:

         下面的例子示範了OCIServerAttach()函數的使用。這段代碼配置設定了伺服器句柄,調用了attach函數,配置設定了服務上下午句柄并且設定了服務上下文句柄中的伺服器上下文句柄。

OCIHandleAlloc( (dvoid *) envhp,            (dvoid**) &srvhp,           (ub4)OCI_HTYPE_SERVER,

                 0,              (dvoid **) 0);

OCIServerAttach( srvhp,         errhp,     (text *) 0,        (sb4) 0,   (ub4)OCI_DEFAULT);

OCIHandleAlloc( (dvoid *) envhp,            (dvoid**) &svchp,           (ub4)OCI_HTYPE_SVCCTX,

0,           (dvoid**) 0);

OCIAttrSet( (dvoid *) svchp,    (ub4) OCI_HTYPE_SVCCTX,           (dvoid*) srvhp,

(ub4) 0,            (ub4)OCI_ATTR_SERVER,                (OCIError *)errhp);

7.1.3         OCIServerDetach()函數

作用:删除OCI操作對一個資料源的通路。

原型:

         Sword      OCIServerDetach(  OCIServer                  *srvhp,

                                                                 OCIError                    *errhp,

                                                                 Ub4                             mode);

參數:

srvhp:一個已經初始化的伺服器上下文句柄,該句柄會被重置為未初始化狀态。該

句柄不會被釋放。

         errhp:可以傳遞給OCIErrorGet()函數來擷取診斷資訊的錯誤句柄。

         mode:說明操作的不同模式。僅有的有效模式是OCI_DEFAULT。

注釋:

         這個函數會删除OCI操作的資料源通路路徑。

7.1.4         OCISessionBegin()函數

作用:建立一個使用者會話并開始一個使用者會話。

原型:

         Sword     OCISessionBegin(   OCISvcCtx                  *svchp,

                                                                 OCIError                    *errhp,

                                                                 OCISession               *usrhp,

                                                                 Ub4                             credt,

                                                                 Ub4                             mode);

參數:

svchp:服務上下午句柄。在svchp中必須有一個有效的伺服器上下文句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

usrhp:一個使用者會話上下文的句柄,函數初始化這個句柄。

credt:說明用來設定使用者會話的憑據。有效值是:

·OCI_CRED_RDBMS—使用使用者名和密碼作為憑據來進行認證。在調用此函數前必須設

置使用者會話句柄中的OCI_ATTR_USERNAME和OCI_ATTR_PASSWORD屬性。

         ·OCI_CRED_EXT—使用外部認證。不使用使用者名或者密碼。

    mode:指定操作模式。有效模式為:

    ·OCI_DEFAULT—預設模式,在此模式中,傳回的使用者會話上下文句柄隻能設定到svchp中已經設定的伺服器上下文句柄上。

    ·OCI_MIGRATE—

    ·OCI_SYSDBA--DBA模式,在這種模式下使用者被授予SYSDBA權限。

    ·OCI_SYSOPER—操作員模式,在這種模式下使用者被授予SYSOPER權限。

    ·OCI_PRELIM_AUTH—。

注釋:

    OCISessionBegin()函數用來向伺服器認證一個使用者。

    OCISessionBegin()函數隻支援對服務上下文句柄中的伺服器句柄所指明的Oracle伺服器進行使用者認證。

例子:

    下面的例子表明了OCISessionBegin()函數的用法。這段代碼配置設定了使用者會話句柄,設定了使用者名和密碼屬性,調用OCISessionBegin()函數并且将使用者會話設定到服務上下文中。

    OCIHandleAlloc((dvoid *)envhp,     (dvoid **)&usrhp,    (ub4)OCI_HTYPE_SESSION,

                           (size_t) 0,                    (dvoid **) 0);

OCIAttrSet((dvoid *)usrhp,     (ub4)OCI_HTYPE_SESSION,            (dvoid *)"hr",

(ub4)strlen("hr"),             OCI_ATTR_USERNAME,                   errhp);

OCIAttrSet((dvoid *)usrhp,     (ub4)OCI_HTYPE_SESSION,   (dvoid *)"hr",

(ub4)strlen("hr"),             OCI_ATTR_PASSWORD,          errhp);

checkerr(errhp,       OCISessionBegin(svchp,         errhp,      usrhp,     OCI_CRED_RDBMS,

OCI_DEFAULT));

OCIAttrSet((dvoid *)svchp,     (ub4)OCI_HTYPE_SVCCTX,             (dvoid *)usrhp,

(ub4)0,             OCI_ATTR_SESSION,         errhp);

7.1.5         OCISessionEnd()函數

作用:終止OCISessionBegin()函數所建立的使用者會話。

原型:

         Sword     OCISessionEnd(      OCISvcCtx                  *svchp,

                                                                 OCIError                    *errhp,

                                                                 OCISession               *usrhp,

                                                                 Ub4                             mode);

參數:

Svchp:服務上下文句柄。必須已經有一個有效的伺服器上下文句柄和使用者會話句柄

連接配接到了svchp。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         usrhp: 取消對該使用者的認證。如果這個參數為NULL,服務上下文句柄中的使用者被取消認證。

         mode: 唯一有效的模式是OCI_DEFAULT。

7.2       句柄和描述符函數

這一節描述OCI句柄和描述符函數。

         表7-2 句柄和描述符函數

7.2.1 OCIHandleAlloc()函數

         作用:傳回一個被配置設定的和初始化的句柄的指針。

         原型:

                  sword       OCIHandleAlloc(       CONST dvoid             *parenth,

                                                                           dvoid                           **hndlpp,

                                                                           ub4                              type,

                                                                           size_t                          xtramem_sz,

                                                                           dvoid                           **usrmempp);

         參數:

         parenth:一個環境句柄。

         hndlpp:傳回一個句柄。

         type:指定要被配置設定的句柄的類型。允許的類型是:

         ·OCI_HTYPE_ENV—配置設定C類型OCIEnv的環境句柄。

    ·OCI_HTYPE_ERROR—配置設定C的OCIError類型的錯誤報告句柄。

    ·OCI_HTYPE_SVCCTX—配置設定C的OCISvcCtx類型的服務上下午句柄。

    ·OCI_HTYPE_STME—配置設定C的OCISvcCtx類型的語句句柄。

    ·OCI_HTYPE_DESCRIBE—配置設定C的OCIDescribe類型的描述句柄。

    ·OCI_HTYPE_SERVER—配置設定C類型為OCIServer的伺服器上下文句柄。

    ·OCI_HTYPE_SESSION—配置設定C類型為OCISession的使用者會話句柄。

    ·OCI_HTYPE_TRANS—配置設定C類型為OCITrans的事務上下文句柄。

    xtramem_sz:指定被配置設定的使用者記憶體。

    usrmempp:傳回被配置設定的xtramem_sz大小的記憶體的指針。

    注釋:

    這個函數傳回一個參數type中指定的類型的句柄指針。執行成功後傳回一個non-NULL類型的句柄。所有被配置設定的句柄都相關于作為輸入參數的父句柄parenthandle—環境句柄。

    當有錯誤發生時,不提供診斷資訊。這個函數執行成功後傳回OCI_SUCCESS,當有錯誤發生時傳回OCI_INVALID_HANDLE。

    将句柄傳至OCI函數前,必須使用OCIHandleAlloc()函數來配置設定句柄。

    調用OCIEnvInit函數來配置設定和初始化環境句柄。

7.2.2         OCIHandleFree()函數

作用:這個函數顯式地釋放一個句柄。

原型:

         sword       OCIHandleFree(       dvoid                  *hndlp,

                                                                 ub4                     type);

參數:

hndlp: OCIHandleAlloc()函數配置設定的句柄。

type:說明要被釋放的句柄的類型。相關的類型有:

·OCI_HTYPE_ENV—配置設定C類型OCIEnv的環境句柄。

    ·OCI_HTYPE_ERROR—配置設定C的OCIError類型的錯誤報告句柄。

    ·OCI_HTYPE_SVCCTX—配置設定C的OCISvcCtx類型的服務上下午句柄。

    ·OCI_HTYPE_STME—配置設定C的OCISvcCtx類型的語句句柄。

    ·OCI_HTYPE_DESCRIBE—配置設定C的OCIDescribe類型的描述句柄。

    ·OCI_HTYPE_SERVER—配置設定C類型為OCIServer的伺服器上下文句柄。

    ·OCI_HTYPE_SESSION—配置設定C類型為OCISession的使用者會話句柄。

    ·OCI_HTYPE_TRANS—配置設定C類型為OCITrans的事務上下文句柄。

注釋:

這個函數釋放type指定類型的句柄的存儲空間。

這個函數傳回OCI_SUCCESS或者OCI_INVALID_HANDLE。

所有的句柄都可以被顯式地釋放。如果父句柄被釋放,則OCI會釋放其子句柄的存儲空

間。

7.2.3         OCIAttrGet()函數

作用:用來擷取一個句柄的屬性。

原型:

         Sword      OCIAttrGet(     CONST     dvoid                 *trgthndlp,

                                                        Ub4                                       trghndltyp,

                                                        Dvoid                                   *attributep,

                                                        Ub4                                       *sizep,

                                                        Ub4                                       attrtype,

                                                        OCIError                              *errhp);

參數:

trgthndlp:句柄的指針。實際的句柄可以是一個語句句柄、一個會話句柄等等。

trgthndltyp:說明句柄的類型。

attributep:屬性值的指針。

sizep:屬性值的大小。因為attributep是dvoid類型的指針,是以size總是以位元組為機關。

因為非字元串屬性的大小是OCI庫已知的,是以這個參數可以置為NULL。對于text*類型的參數,該參數必須是一個ub4類型的指針,其提供字元串的長度。

         attrtype:擷取的屬性的類型。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

注釋:

         這個函數用來擷取一個句柄的特定屬性。

7.2.4             OCIAttrSet()函數

作用:這個函數用來設定一個句柄或者描述符的屬性。

原型:

         sword      OCIAttrSet(     dvoid                 *trgthndlp,

                                                        ub4                    trghndltyp,

                                                        dvoid                 *attributep,

                                                        ub4                    size,

                                                        ub4                    attrtype,

                                                        OCIError           *errhp);

參數:

trgthndlp:要修改的句柄的指針。

trghndltyp:句柄的類型。

attributep:屬性值的指針。屬性值會被複制到目标句柄中。如果屬性值為指針,則會複

制指針而不會複制指針的内容。

         size:屬性值的大小。對OCI已經知道的屬性,可以直接傳遞0。對text*類型的屬性,則需要傳遞ub4類型的字元串的長度。

         attrtype:被設定的屬性的類型。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

7.2.5             OCIDescriptorAlloc()函數

作用:為儲存描述符或者LOB定位符配置設定空間。

原型:

         sword       OCIDescriptorAlloc(         CONST      dvoid                  *parenth,

                                                                 dvoid                                     **descpp,

                                                                 ub4                                        type,

                                                                 size_t                                   xtramem_sz,

                                                                 dvoid                                     **usrmempp);

參數:

parenth:一個環境句柄。

descpp:傳回一個描述符或者LOB定位符。

type:指定描述符的類型或者LOB定位符。

·OCI_DTYPE_SNAP—

·OCI_DTYPE_LOB—用于配置設定OCILobLocator類型的LOB定位符(對于BLOB或者CLOB).

·OCI_DTYPE_FILE—用于OCILobLocator類型的FILE值類型的定位符。

xtramem_sz:指定應用程式為使用者配置設定的記憶體的數量。

usrmempp:傳回xtramem_sz大小的記憶體的指針。

注釋:

傳回type參數中指定的類型的描述符的指針。執行成功後傳回非空的描述符或者LOB

定位符。

         如果執行成功,函數傳回OCI_SUCCESS,否則傳回OCI_INVALIDE_HANDLE。

7.2.6             OCIDescriptorFree()函數

作用;這個函數用來釋放之前配置設定的描述符。

原型:

                  sword       OCIDescriptorFree(          dvoid                  *descpp,

                                                                                    ub4                     type);

參數:

         descpp:一個被配置設定的描述符。

         type:指出要被釋放的存儲空間的類型。

注釋:

         這個函數釋放同一個描述符相連的存儲空間。傳回OCI_SUCCESS或者OCI_INVALID_HANDLE。所有的描述符都可以被顯式地釋放,但是,當環境句柄被釋放後,其描述符也會被釋放。

7.2.7             OCIParamGet()函數

作用:傳回一個描述句柄或者語句句柄中指定位置的參數描述符。

原型:

         sword       OCIParamGet(                   CONSTdvoid             *hndlp,

                                                                 ub4                              htype,

                                                                 OCIError                     *errhp,

                                                                 dvoid                           **parmdpp,

                                                                 ub4                              pos);

參數:

hndlp:一個語句句柄或者描述句柄。OCIParamGet()函數将會為這個句柄傳回一個參數描述符。

htype:指定傳遞至參數hndlp的句柄的類型。有效的類型是:

·OCI_DTYPE_PARAM,參數描述符。

·OCI_HTYPE_COMPLEXOBJECT,複雜對象擷取句柄。

·OCI_HTYPE_STMT,語句句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

parmdpp:參數pos指定的位置的參數描述符。

pos:說明語句句柄或者描述句柄中的位置。将會為這個位置傳回一個參數描述符。

注釋:

這個函數傳回描述句柄或者語句句柄中指定位置的參數描述符。參數描述符總是在OCI庫内部進行配置設定的。可以通過OCIDescriptorFree()函數來釋放它們。

7.3       綁定、定義和描述函數

這部分描述綁定、定義和描述函數。

表7-3  綁定、定義和描述函數

7.3.1 OCIBindByName()函數

作用:建立程式變量和一個SQL語句中的占位符之間的結合。

原型:

                  sword       OCIBindByName(     OCIStmt                     *stmtp,

                                                                           OCIBind                      **bindpp,

                                                                           OCIError                     *errhp,

                                                                           CONSTtext              *placeholder,

                                                                           sb4                               placeh_len,

                                                                           dvoid                           *valuep,

                                                                           sb4                               value_sz,

                                                                           ub2                               dty,

                                                                           dvoid                           *indp,

                                                                           ub2                              *alenp,

                                                                           ub2                              *rcodep,

                                                                           ub4                              maxarr_len,

                                                                           ub4                              *curelep,

                                                                           ub4                              mode);

參數:

stmtp:被處理的SQL或者PL/SQL語句的語句句柄。

bindpp:儲存這個函數隐式配置設定的綁定句柄的指針。綁定句柄維護了某個特定的輸

入值的所有的綁定資訊。當語句句柄被釋放時,這個綁定句柄會被隐式地釋放。作為輸入/輸出參數,在輸入時,指針的是必須為NULL或者是一個有效的綁定句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         placeholder:由名字來指定的占位符,其對應着同語句句柄結合的語句中的一個變量。

         placeh_len:占位符的長度。以位元組為機關。

         valuep: 指向dty參數制定的類型的數值的指針。

         value_sz:萬能指針valuep指向的數值的長度。對于客戶應用程式不知道其大小的描述符、定位符或者REFs,我們使用sizeof(OCILobLocator*)。

         dty:指定被綁定的數值的資料類型。

         Indp:訓示器變量的指針。對于除SQLT_NTY之外的資料類型,該指針為指向sb2類型的指針或者一個sb2的數組。

         alenp:數組袁術的實際長度的指針。

         rcodep:指向一個字段級傳回代碼數組的指針。

         maxarr_len:

         curelep:

         mode:模式。有效的模式有

         ·OCI_DEFAULT—預設模式。

    ·OCI_BIND_SOFT。

    ·OCI_DATA_AT_EXEC。

注釋:

這個函數用來執行基本的綁定操作。綁定會在一個程式變量的位址和一個SQL語句或者PL/SQL塊中的占位符之間建立結合。這個函數也指定了被綁定的資料的類型,也說明了在運作時提供資料的方式。

         這個函數會隐式地配置設定綁定句柄,綁定句柄由bindpp參數指明。如果**bindpp是一個非空指針,OCI假定這個指針指向一個之前配置設定的有效的句柄。

7.3.2 OCIBindByPos()函數

作用:建立程式變量和一個SQL語句中的占位符之間的結合。

原型:

                   sword       OCIBindByPos(         OCIStmt*                                      *stmtp,

                                                                 OCIBind                               **bindpp,

                                                                 OCIError                              *errhp,

                                                                 ub4                                        position,

                                                                 dvoid                                     *valuep,

                                                                 Sb4                                        value_sz,

                                                                 ub2                                        dty,

                                                                 dvoid                                     *indp,

                                                                 ub2                                        *alenp,

                                                                 ub2                                        *rcodep,

                                                                 ub4                                        maxarr_len,

                                                                 ub4                                        *curelep,

                                                                 ub4                                        mode);

參數:

stmtp:被處理的SQL或者PL/SQL語句的語句句柄。

bindpp:儲存這個函數隐式配置設定的綁定句柄的指針。綁定句柄維護了某個特定的輸

入值的所有的綁定資訊。當語句句柄被釋放時,這個綁定句柄會被隐式地釋放。作為輸入/輸出參數,在輸入時,指針的是必須為NULL或者是一個有效的綁定句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         position:說明占位符的位置。

         valuep: 指向dty參數制定的類型的數值的指針。

         value_sz:萬能指針valuep指向的數值的長度。對于客戶應用程式不知道其大小的描述符、定位符或者REFs,我們使用sizeof(OCILobLocator*)。

         dty:指定被綁定的數值的資料類型。

         Indp:訓示器變量的指針。對于除SQLT_NTY之外的資料類型,該指針為指向sb2類型的指針或者一個sb2的數組。

         alenp:數組袁術的實際長度的指針。

         rcodep:指向一個字段級傳回代碼數組的指針。

         maxarr_len:

         curelep:

         mode:模式。有效的模式有

注釋:

這個函數用來執行基本的綁定操作。綁定會在一個程式變量的位址和一個SQL語句或者PL/SQL塊中的占位符之間建立結合。這個函數也指定了被綁定的資料的類型,也說明了在運作時提供資料的方式。

         這個函數會隐式地配置設定綁定句柄,綁定句柄由bindpp參數指明。如果**bindpp是一個非空指針,OCI假定這個指針指向一個之前配置設定的有效的句柄。

7.3.3 OCIDefineByPos()函數

作用:建立所選字段中的一個字段和輸出緩沖區的結合。

原型:

                   Sword       OCIDefineByPos(     OCIStmt            *stmtp,

                                                                           OCIDefine         **defnpp,

                                                                           OCIError           *errhp,

                                                                           Ub4                    position,

                                                                           Dvoid                 *valuep,

                                                                           Sb4                     value_sz,

                                                                           Ub2                    dty,

                                                                           Dvoid                 *indp,

                                                                           Ub2                    *rlenp,

                                                                           Ub2                    *rcodep,

                                                                           Ub4                    mode);

參數:

         stmtp:請求SQL查詢的語句句柄。

         defnpp:指向定義句柄指針的指針。如果這個參數為NULL,這個函數将會隐式地配置設定定義句柄。在重新定義的情況下,一個非NULL句柄可以傳遞到這個參數。這個句柄用來儲存某個字段的定義資訊。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         position:這個值在所選字段中的位置。位置是從1開始的,并且從左向右遞增。

         valuep:指向dty參數所指明的類型的緩沖區或者緩沖區數組的指針。對于LOB字段,緩沖區指針必須是OCILobLocator類型的LOB定位符的指針。

         value_sz: valuep指針所指向的緩沖區的大小。

         dty:資料類型。用于指明所選字段如何轉換為程式變量。

         indp:訓示器變量或者數組的指針。對于标準變量,該指針為指向sb2類型的的指針或者是一個sb2類型的數組。

         rlenp:指向擷取到的資料的長度的數組的指針。Rlenp中的每個元素都是資料的長度。

         rcodep:字段級傳回代碼數組的指針。

         mode:模式。有效的模式為:

         ·OCI_DEFAULT—預設模式。

    ·OCI_DEFINE_SOFT.

    ·OCI_DYNAMIC_FETCH.

注釋:

這個函數定義一個将要從Oracle伺服器中擷取資料的輸出緩沖區。這個函數會為所選字段隐式地配置設定定義句柄。如果*defnpp為一個非空指針,OCI假設這個指針指向一個之前通過OCIHandleAlloc()函數或者OCIDefineByPos()函數配置設定的有效的句柄。

擷取LOB字段類型時,緩沖區指針必須是一個指向OCILobLocator類型的LOB定位符的指針,通過OCIDescriptorAlloc()函數來配置設定它。LOB字段傳回LOB定位符,而不是LOB資料。

7.4       語句函數

這部分描述語句函數。表7-4列出了語句函數。

         表 7-4 語句函數

         7.4.1 OCIStmtPrepare()函數

         作用:為執行SQL或者PL/SQL語句而做準備。

         原型:

                  sword       OCIStmtPrepare(     OCIStmt                     *stmtp,

                                                                           OCIError                     *errhp,

                                                                           CONST      text           *stmt,

                                                                           ub4                              stmt_len,

                                                                           ub4                              language,

                                                                           ub4                              mode);

         參數:

         stmtp:語句句柄。與這個語句句柄相連的語句将會被執行。

errhp:錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         stmt:語句。被執行的SQL或者PL/SQL語句。必須是一個NULL結尾的字元串。

         stmt_len:語句的長度。

         language:解析語句的文法。可能的值有:

         ·OCI_V7_SYNTAX—V7 Oracle解析文法。

    ·OCI_NTV_SYNTAX—解析的文法依賴于伺服器的版本。

         mode:模式。唯一可能的值是:

         ·OCI_DEFAULT—預設模式。

         注釋:

         一個OCI應用程式使用這個函數來為執行一個SQL或者PL/SQL語句做準備。OCIStmtPrepare()函數也定義了一個應用程式請求。

         這個函數并不建立語句句柄和資料庫伺服器之間的連接配接。

         7.4.2 OCIStmtExecute()函數

         作用:連接配接一個應用程式請求值伺服器。

         原型:

         sword       OCIStmtExecute(     OCISvcCtx                                     *svchp,

                                                                 OCIStmt                                        *stmtp,

                                                                 OCIError                                       *errhp,

                                                                 ub4                                                 iters,

                                                                 ub4                                                 rowoff,

                                                                 CONST  OCISnapshot              *snap_in,

                                                                 OCISnapshot                                *snap_out,

                                                                 ub4                                                 mode);

         參數:

         svchp:服務上下文句柄。

         stmtp:語句句柄。它定義了語句并且連接配接資料到伺服器。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         iters:對于非SELECT語句,語句執行的次數等于iters-rowoff。

         對于SELECT語句,如果iters為非0,則必須已經完成了語句句柄的定義操作。語句的執行将擷取iters行資料進入預定義的緩沖區中并且根據預擷取行數prefetch row count預擷取更多行。如果我們不知道SELECT語句會傳回多少行,則把iters設定為0。

         對于非SELECT語句,如果iters=0,則函數傳回一個錯誤。

         rowoff:起始索引。關于多行執行的數組綁定中的起始索引。

         snap_in:該參數為可選參數。如果使用該參數,其必須指向一個OCI_DTYPE_SNAP類型的快照描述符。

         snap_out:該參數為可選參數。如果使用該參數,其必須指向OCI_DTYPE_SNAP類型的描述符。

         mode:模式包括

         ·OCI_BATCH_ERRORS

    ·OCI_COMMIT_ON_SUCCESS—當一個語句在此模式下執行時,如果語句成功執行,則執行完成後目前的事務會被送出。

    ·OCI_DEFAULT—預設模式,使用此模式來調用OCIStmtExecute()函數。它會隐式地傳回關于所選字段的描述資訊。

    ·OCI_DESCRIBE_ONLY—描述模式。這個模式用于在執行前擷取查詢的描述資訊。以此模式調用OCIStmtExecute()函數并不執行語句,而是傳回所選字段的描述資訊。為提高性能,建議使用者使用預設模式。

    ·OCI_EXACT_FETCH—

    ·OCI_PARSE_ONLY—

    ·OCI_STMT_SCROLLABLE_READONLY--

         注釋:

         這個函數用來執行一個已經準備好的SQL語句。調用這個函數時,應用程式與伺服器建立請求。

         7.4.3 OCIStmtFetch()函數

         作用:擷取查詢的結果。

         原型:

                   Sword       OCIStmtFetch(          OCIStmt                     *stmtp,

OCIError                     *errhp,

Ub4                              nrows,

Ub2                              orientation,

Ub4                              mode);

         參數:

         Stmtp:語句句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         nrows:從目前位置擷取的行數。

         orientation:在9.0版本以前,唯一可以接受的值是OCI_FETCH_NEXT。

         mode:模式。傳入OCI_DEFAULT。

         注釋:

         如果預擷取的行數足夠的話,這個擷取函數是一個本地調用。

         如果讀取的是LOB字段,擷取到的是LOB定位符。

         當擷取不到資料時這個函數傳回OCI_NO_DATA。

7.5       LOB函數

這部分描述使用LOB定位的LOB函數。

         7.5.1 OCILobGetLength()函數

         作用:擷取LOB的長度。

         原型:

                  Sword      OCILobGetLength(  OCISvcCtx                           *svchp,

                                                                           OCIError                              *errhp,

                                                                           OCILobLocator                            *locp,

                                                                           Ub4                                       *lenp);

         參數:

         svchp:服務上下文句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         locp:引用LOB的LOB定位符。

         lenp:如果LOB不為空,則其為LOB的長度。對于字元型LOB,它是字元的數量,對于二進制LOB和BFILE,它是LOB的位元組數量。

         注釋:

         擷取LOB的長度。空的LOB的長度為0。

         7.5.2 OCILobRead()函數

         作用:讀取LOB或者BFILE的一部分到緩沖區。

         原型:

                  sword       OCILobRead(   OCISvcCtx                           *svchp,

                                                                 OCIError                              *errhp,

                                                                 OCILobLocator                            *locp,

                                                                 ub4                                        *amtp,

                                                                 ub4                                        offset,

                                                                 dvoid                                     *bufp,

                                                                 ub4                                        bufl,

                                                                 dvoid                                     *ctxp,

                                                                 OCICallbackLobRead        (cbfp)

                                                                                                                (dvoid                          *ctxp,

                                                                                                                CONST  dvoid          *bufp,

                                                                                                                Ub4                              len,

                                                                                                                Ub1                              piece)

                                                                 ub2                                        csid,

                                                                 ub1                                        csfrm);

         參數:

         svchp:服務上下午句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         locp:引用LOB或者BFILE的一個LOB或者BFILE定位符。

         amtp:位元組的或者字元的數量。如下表所示

         offset:表示從LOB值開始處的偏移量。

         bufp:儲存LOB值的緩沖區的指針。假定緩沖區的長度為bufl。

         bufl:緩沖區的長度。

         ctxp:回調函數的上下文指針。可以為NULL。

         cbfp:

         ctxp:回調函數的上下文。可以為NULL。

         Bufp:

         Len:

         Piece:

         Csid:

         Csfrm:

         注釋:

         這個從LOB或者BFILE中讀取一部分到一個緩沖區中。從空的LOB或者BFILE中讀取值是一個錯誤。

         7.5.3 OCILobWrite()函數

         作用:将緩沖區中的資料寫入到LOB中。

         原型:

                  Sword       OCILobWrite(  OCISvcCtx                           *svchp,

                                                                 OCIError                              *errhp,

                                                                 OCILobLocator                            *locp,

                                                                 ub4                                       *amtp,

                                                                 ub4                                        offset,

                                                                 dvoid                                     *bufp,

                                                                 ub4                                        buflen,

                                                                 ub1                                        piece,

                                                                 dvoid                                     *ctxp,

                                                                 OCICallbackLobWrite       (cbfp)

                                                                                                                (dvoid       *ctxp,

                                                                                                                Dvoid        *bufp,

                                                                                                                Dvoid        *bufp,

                                                                                                                Ub4           *lenp,

                                                                                                                Ub1           *piecep)

                                                                 ub2                                        csid,

                                                                 ub1                                        csfrm);

         參數:

         svchp:服務上下午句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         locp:引用LOB或者BFILE的一個LOB或者BFILE定位符。

         amtp:位元組的或者字元的數量。如下表所示

         offset:表示從LOB值開始處的偏移量。

         bufp:儲存LOB值的緩沖區的指針。假定緩沖區的長度為bufl。

         bufl:緩沖區的長度。

         ctxp:回調函數的上下文指針。可以為NULL。

         cbfp:

         ctxp:回調函數的上下文。可以為NULL。

         Bufp:

         Len:

         Piece:

         Csid:

         Csfrm:

         注釋:

         将緩沖區中的資料寫入到LOB字段中。

7.6       事務函數

這部分描述事務相關函數。表7-5列出了所有的事務相關函數。

表7-5 事務相關函數

         7.6.1 OCITransCommit()函數

         作用:送出與指定的服務上下午聯系的事務。

         原型:

                  Sword       `OCITransCommit(  OCISvcCtx                  *svchp,

                                                                           OCIError                     *errhp,

                                                                           Ub4                              flags);

         參數:

         Svchp:服務上下午句柄。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         flags:如果事務不是分布式的,則flags可以被忽略,将OCI_DEFAULT作為其值。

         注釋:

         與目前的服務上下午句柄相連的事務被送出。

         7.6.2 OCITransRollback()函數

         作用:復原目前事務。

         原型:

                   Sword       OCITransRollback(   dvoid                           *svchp,

                                                                           OCIError                     *errhp,

                                                                           Ub4                              flags);

         參數:

         svchp:服務上下文句柄。服務上下午句柄中的事務被復原。

errhp: 錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數獲

取診斷資訊。

         flags:必須為此參數傳遞OCI_DEFAULT。

         注釋:

         該函數復原目前事務。

7.7       線程管理函數

這部分描述線程管理函數,表16-9列出了所有的線程管理函數

表16-9 線程管理函數Thread Management functions

7.7.1 OCIThreadProcessInit()函數

作用:執行OCIThread程序初始化。

原型:

         Void           OCIThreadProcessInit();

注釋:

         是否需要調用這個函數依賴于OCI線程如何被使用。

         在一個單線程應用程式中,可以調用這個函數也可以不調用這個函數。如果它被調用了,則對它的第一次調用必須早于任何其他的OCIThread函數。之後的對OCIThreadProcessInit()函數的調用将沒有任何限制:它們沒有任何作用。        

在一個多線程應用程式中,這個函數必須被調用。對它的第一次調用必須早于任何其他的OCIThread函數調用。之後的對OCIThreadProcessInit()函數的調用将沒有任何限制:它們沒有任何作用。

7.7.2 OCIThreadInit()函數

         作用:初始化OCIThread上下文

         原型:

                  Sword       OCIThreadInit(         dvoid                  *hndl,

                                                                 OCIError           *err);

         參數:

         hndl: OCI環境句柄或者使用者會化句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數

擷取診斷資訊。

         注釋:

         OCIThreadInit()函數第一次被調用時,它初始化OCI線程上下文。它以依賴于系統的方式來儲存一個指向該上下文的指針。之後對OCIThreadInit()函數的調用會傳回同樣的上下文。

         每一個對OCIThreadInit()函數的調用都比對一個對OCIThreadTerm()函數的調用。

7.7.3 OCIThreadTerm()函數

         作用:釋放OCIThread上下文。

         原型:

                  Sword       OCIThreadTerm(      dvoid                  *hndl,

                                                                           OCIError           *err);

         參數:

         hndl: OCI環境句柄或者使用者會化句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至

OCIErrorGet()函數擷取診斷資訊。

         注釋:

         這個函數必須與每一個對OCIThreadInit()函數的調用相比對。

         對OCIThreadTerm()函數的并發調用是安全的。OCIThreadTerm()函數不做任何事情直到它被調用的次數和OCIThreadInit()函數被調用的次數相同。當調用次數相同時,它終止OCIThread層并且釋放配置設定給上下文的記憶體。一旦這發生了,該上下文就不能被重用。需要調用OCIThreadInit()函數來擷取一個新的OCIThread上下文。

7.7.4 OCIThreadIdInit()函數

         作用:配置設定和初始化線程ID

         原型:

                   Sword       OCIThreadIdInit(      dvoid                  *hndl,

                                                                           OCIError           *err,

                                                                           OCIThreadId    **tid);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tid:要初始化的線程ID Thread ID的指針。

7.7.5 OCIThreadIdGet()函數

         作用:擷取調用該函數的線程的OCIThreadId。

         原型:

                  Sword       OCIThreadIdGet(     dvoid                  *hndl,

                                                                           OCIError           *err,

                                                                           OCIThreadId    *tid);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tid:其指向儲存調用線程的ID的地方。

         注釋:

         tid應該被OCIThradIdInit()函數來初始化。當OCIThread用于單線程環境時,OCIThreadIdGet()函數将始終放置相同的值在tie所指向的地方。重要的并不是這個數值。重要的是這個值不為NULL,thread ID總是相同的值。

7.7.6 OCIThreadIdNull()函數

         作用:檢視一個給定的OCIThreadId是否是NULL thread ID

         原型:

                  Sword       OCIThreadIdNull( dvoid                      *hndl,

                                                                    OCIError              *err,

                                                                    OCIThreadId      *tid,

                                                                    boolean               *result);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tid:所要檢測的OCIThreadIde的指針。

         result:指向結果的指針。

         注釋:

         如果線程ID為NULL線程ID,result被設定為TRUE。否則,result被設定為FALSE。tid應該被OCIThreadIdInit()初始化。

7.7.7 OCIThreadIdSame()函數

         作用:檢測兩個OCIThreadId是否代表同一個線程

         原型:

                  Sword       OCIThreadIdSame( dvoid                   *hndl,

                                                                           OCIError           *err,

                                                                           OCIThreadId    *tid1,

                                                                           OCIThreadId    *tid2,

                                                                           Boolean             *result);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         注釋:

7.7.8 OCIThreadMutexInit()函數

         作用:配置設定和初始化一個互斥mutex。

         原型:

                   Sword       OCIThreadMutexInit(      dvoid                           *hndl,

                                                                                    OCIError                    *err,

                                                                                    OCIThreadMutex     **mutex);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         mutex:要初始化的互斥。

         注釋:

         所有的互斥在使用前必須被初始化。

         多個線程不能同時初始化同一個互斥。并且,在一個互斥被銷毀前,其不能被重新初始化。

7.7.9 OCIThreadMutexDestroy()函數

         作用:銷毀互斥并釋放其所占用的空間。

         原型:

                  Sword       OCIThreadMutexDestroy(       dvoid                           *hndl,

                                                                                             OCIError                     *err,

                                                                                             OCIThreadMutex     **mutex);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         mutex:要銷毀的互斥。

         注釋:

         每一個不再被使用的互斥一定要被銷毀。

         銷毀一個未被初始化的互斥或者一個目前被一個線程持有的互斥并不是錯誤的。互斥的銷毀不能與其他對互斥的操作并發執行。一個互斥在其被銷毀後,其不能再被使用。

7.7.10 OCIThreadMutexAcquire()函數

         作用:為調用這個函數的線程擷取互斥

         原型:

                   Sword       OCIThreadMutexAcquire(dvoid                          *hndl,

                                                                                     OCIError                            *err,

                                                                                     OCIThreadMutex  *mutex);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         mutex:所要擷取的互斥。

         注釋:

         如果互斥被其他線程持有,則該線程會被阻塞直到它能夠擷取互斥。

         擷取一個未初始化的線程是違規的。

7.7.11 OCIThreadMutexRelease()函數

         作用:釋放一個互斥mutex

         原型:

                  Sword       OCIThreadMutexRelease(dvoid                        *hndl,

                                                                                     OCIError                            *err,

                                                                                     OCIThreadMutex  *mutex);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         mutex:要釋放的互斥。

         注釋:

         如果有線程阻塞在這個互斥中,它們中的一個線程會獲得這個互斥并且成為不阻塞的。

         釋放一個未初始化的互斥的違規的。一個線程釋放其不擁有的互斥也使違規的。

7.7.12 OCIThreadIdSetNull()函數

         作用:對給定的OCIThreadId設定其為NULL線程ID。

         原型:

                  Sword       OCIThreadIdSetNull(        dvoid                  *hndl,

                                                                                    OCIError           *err,

                                                                                    OCIThreadId    *tid);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         OCIThreadId:指向OCIThreadId,其會被指派為NULL線程ID。

         注釋:

         Tid應該已經被OCIThreadIdInit()函數初始化。

7.7.13 OCIThreadIdSet()函數

         作用:将源OCIThreadId的值賦給另一個OCIThreadId

         原型:

                  Sword       OCIThreadIdSet(      dvoid                  *hndl,

                                                                           OCIError           *err,

                                                                           OCIThreadId    *tidDest,

                                                                           OCIThreadId    *tidSrc);

         參數:

         hndl:OCI環境句柄或者使用者會話句柄。

         err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tidDest:目标ThreaId,指向所要設定的OCIThreadId的位置。

         tidSrc:源ThreadId,指向來源OCIThreadId。

         注釋:

         tid應該被OCIThreadIdInit()函數初始化。

7.7.14 OCIThreadCreate()函數

         作用:建立新的線程。

         原型:

                   Sword       OCIThreadCreate(   dvoid                           *hndl,

                                                                           OCIError                    *err,

                                                                           Void(*start)               (dvoid*),

                                                                           Dvoid                          *arg,

                                                                           OCIThreadId             *tid,

                                                                           OCIThreadHandle    *tHnd);

         參數:

         hndl:OCI環境句柄或者OCI使用者會話句柄。

         err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         start:新的線程開始執行的函數。

         arg:傳遞給start所指向的函數的參數。

         tid:如果不為NULL,則為新線程擷取該ID。

         tHnd:如果不為NULL,則為新線程擷取該句柄。

         注釋:

         新線程通過執行對start所指向的函數并擷取arg參數開始運作。當那個函數傳回時,新的線程将終止。線程函數不應傳回一個值而應該接收一個參數。隻有在tHnd為非空的情況下,每一個OCIThreadCreate()函數的調用必須比對一個OCIThreadClose()函數的調用。

         tid應該被OCIThreadIdInit()函數初始化并且tHnd應該被OCIThreadHndInit()函數初始化。

7.7.15 OCIThreadClose()函數

         作用:關閉一個線程句柄。

         原型:

                  Sword       OCIThreadClose(     dvoid                           *hndl,

                                                                           OCIError                     *err,

                                                                           OCIThreadHandle    *tHnd);

         參數:

         hndl:OCI環境句柄或者OCI使用者會話句柄。

         err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tHnd:所要關閉的OCIThread句柄。

         注釋:

         tHnd應該被OCIThreadHndInit()函數初始化。在調用OCIThreadClose()函數後,由同一個OCIThreadCreate()調用傳回的線程句柄和線程ID都變為無效。

7.7.16 OCIThreadHndInit()函數

         作用:配置設定和初始化線程句柄

         原型:

                   Sword       OCIThreadHndInit(  dvoid                           *hndl,

                                                                           OCIError                    *err,

                                                                           OCIThreadHandle    **thnd);

         參數:

         hndl:OCI環境句柄或者OCI使用者會話句柄。

         err: OCI錯誤句柄,當有錯誤發生時,我們可以将該錯誤句柄傳遞至OCIErrorGet()函數擷取診斷資訊。

         tHnd:所要關閉的OCIThread句柄的指針的位址。

7.8       

8.     句柄和描述符屬性

這部分描述OCI句柄和描述符的屬性,可以通過OCIAttrGet()函數來讀取屬性,OCIAttrSet()

函數來設定屬性。

         各種句柄的屬性可以被讀取或者修改。

8.1 服務上下文句柄

         8.1.1 OCI_ATTR_SERVER屬性

          模式:讀寫模式

          作用:當讀取時,傳回指向服務上下文句柄的伺服器上下文的指針。修改時,會設定服務上下午的伺服器上下文屬性。

          屬性值的資料類型:OCIServer**/OCIServer*

         8.1.2 OCI_ATTR_SESSION屬性

          模式:讀寫模式

          作用:當讀取時,傳回服務上下文句柄的認證上下文屬性的指針。當修改時,設定服務上下文句柄的認證上下文屬性。

           屬性值的資料類型:OCISession**/OCISession*

8.2 使用者會話句柄

8.2.1 OCI_ATTR_USERNAME屬性

          模式:寫模式

          作用:指定用于使用者認證的使用者名。

          屬性值的資料類型:OraText*

         8.2.2 OCI_ATTR_PASSWORD屬性

          模式:寫模式

          作用:指定用于使用者認證的密碼。

          屬性值的資料類型:OraText*      

9.     OCI示例程式

Oracle提供了表明OCI使用方式的示例程式。表9-1列出了這些示例程式

         表9-1 OCI示例程式

10.  OracleC++ Call Interface

Oracle C++ Call Interface是用于C++程式操作Oracle資料庫的API。OCCI使C++程式員能

夠利用Oracle資料庫操作手段,包括SQL語句處理和對象操作。

10.1   建立一個OCII應用程式

編譯和連接配接OCII程式的方式與編譯連接配接非資料庫應用程式的方式一樣。如圖10-1所示:

圖10-1

10.2   程式設計方法

這部分描述使用OCCI開發C++應用程式來操作關系型資料庫的基本知識。

10.2.1 連接配接至資料庫

10.2.1.1 建立和終止一個環境

所有的OCCI操作都發生在環境類Environment class的上下文中。OCCI環境提供了應用程式模式和使用者指定的記憶體管理函數。下列代碼顯示了如何建立OCCI環境。

Environment *env = Environment::createEnvironment();

所有由createXXX函數建立的OCCI對象都必須顯式地終止,在合适的時候,我們也可以顯式地終止環境。下列代碼顯示了如何終止OCCI環境。

Environment::terminateEnvironment(env);

另外OCCI環境的作用于要大于任何一個在OCCI環境中建立的對象的作用域。下面的代碼顯示了這個概念:

         const string userName = "SCOTT";

const string password = "TIGER";

const string connectString = "";

Environment *env = Environment::createEnvironment();

{

Connection *conn = env->createConnection(userName,password, connectString);

Statement *stmt = conn->createStatement("SELECTblobcol FROM mytable");

ResultSet *rs = stmt->executeQuery();

rs->next();

Blob b = rs->getBlob(1);

cout << "Length of BLOB : " <<b.length();

.

.

.

stmt->closeResultSet(rs);

conn->terminateStatement(stmt);

env->terminateConnection(conn);

}

Environment::terminateEnvironment(env);

我們可以使用CreateEnvironment函數的模式mode參數來指定我們的應用程式的模式:

·運作在多線程環境中(THREAD_MUTEXED或者THREADED_UNMUTEXED)

·使用對象(OBJECT)

·使用共享資料結構(SHARED)

10.2.1.2 打開和關閉一個連接配接

環境類Environment class是建立連接配接類Connection class對象的工廠類。我們首先建立一個環境執行個體,然後通過createConnection方法讓使用者連接配接到資料庫伺服器。

下面的代碼建立了一個環境執行個體并且用它為使用者scott密碼tiger建立了一個資料庫連接配接。

Environment *env = Environment::createEnvironment();

Connection *conn = env->createConnection("scott","tiger");

在會話結束時,我們需要使用terminateConnection方法關閉連接配接。另外OCCI環境應該被顯式地終止。

env->terminateConnection(conn);

Environment::terminateEnvironment(env);

10.3   執行SQL、DDL和DML語句

在OCCI中,我們通過語句類Statement Class來執行SQL指令。

10.3.1 建立一個環境句柄

使用連接配接對象connection的createStatement方法建立語句句柄Statement Handle,如下

所示:

         Statement *stmt     = conn->createStatement();

10.3.2 建立語句句柄來執行SQL指令

         建立語句句柄之後,通過調用execute、executeUpdate、executeArrayUpdate或者executeQuery方法來執行SQL指令。這些方法用于以下方面:

         ·execute:執行非特定類型的語句

    ·executeUpdate:執行DML和DDL語句

    ·executeQuery:執行一個查詢

    ·executeArrayUpdate:執行多個DML語句

    建立資料庫表

    使用executeUpdate方法,下面的代碼顯示了如何建立資料庫表:

    stmt->executeUpdate(“CREATE  TABLE basket_tab

                    (fruit   VARCHAR2(30),  quantity  NUMBER)”);

    向資料庫表中插入資料

    同樣,我們可以通過executeUpdate方法來執行一個SQL INSERT語句。

    Stmt->executeUpdate(“INSERT  INTO basket_tab  VALUES(‘MANGOES’,3)”);

    重複使用語句句柄

    我們可以重複使用一個語句句柄來執行多次SQL語句。例如,使用不同的參數來重複執行相同的語句,通過語句句柄的setSQL方法來說明所要執行的語句。

    stmt->setSQL(“INSERT  INTO basket_tab  VALUES(:1, :2)”);

    我們可移植性這個SQL語句我們想要的次數。如果我們想執行其他SQL語句,隻需重置語句句柄。例如:

    stmt->setSQL(“SELECT  * FROM  basket_tab  WHERE quantity  >= :1”);

    我們可以通過getSQL方法擷取目前語句句柄的内容。

    終止語句句柄

    我們需要顯式地終止和釋放一個語句:

    Connection::conn->terminateStatement(Statement*stmt);

10.4   OCCI環境中的SQL語句的種類

在一個OCCI環境中有三種SQL語句。

·标準語句—含有指定值的SQL指令。

·參數化語句—有參數或者綁定變量的語句。

·可調用語句—調用儲存的PL/SQL語句。

标準語句是參數化語句的全集,參數化語句是可調用語句的全集。

10.4.1 标準語句

上面的兩個例子描述了DDL和DML指令。例如

stmt->setSQL(“INSERT  INTO basket_tab  VALUES(:1, :2)”);

stmt->executeUpdate(“INSERT INTO basket_tab

VALUES(‘MANGOES’, 3)”);

         這兩個例子都是關于标準語句的例子。CREATE  TABLE語句說明了表名(basket_tab),INSERT語句說明了要被插入的值(‘MANGOES’,3)。

10.4.2      參數化語句

我們通過為語句中的輸入變量設定占位符來執行同樣的語句。因為這些語句能夠通過參

數來接收輸入。

         例如,如果我們想使用不同的參數來執行INSERT語句。我們首先使用語句句柄的setSQL方法來指明語句。

         Stmt->setSQL(“INSERT  IINTO basket_tab  VALUES(:1,  :2)”);

         然後調用setxxx方法來指明參數,xxx代表參數的類型。下面的例子調用了setString和setInt方法來為第一個參數和第二個參數輸入值。

         插入一行

         Stmt->setString(1, “Banana”);                  //第一個參數的值

         Stmt->setInt(2, 5)                                         //第二個參數的值

         指明參數後,我們将這些值插入到資料庫中。

         Stmt->executeUpdate();                    //執行語句

         插入另一行資料:

         Stmt->setString(1, “Apples”);           //第一個參數的值

         Stmt->setInt(2, 9);                              //第二個參數的值

         再插入一行資料。

         stmt->executeUpdate();                    //執行語句

10.5   執行SQL查詢

查詢傳回的結果為結果集result set。

10.6   OCCI類和方法

表10-1列出了OCCI類。

表10-1 OCCI類

Overview of OCI Multithreaded Development

         Threads are lightweight processesthat exist within a larger process. Threads share the same code and data segmentsbut have their own program counters, machine registers, and stacks. Global andstatic variables are common to all threads, and a mutual exclusivity mechanismis required to manage access to these variables from multiple threads within anapplication.

         Once spawned, threads runasynchronously with respect to one another. They can access common dataelements and make OCI calls in any order: Because of this shared access to dataelements, a synchronized mechanism is required to maintain the integrity ofdata being accessed.

         The mechanism to manage data accesstakes the form of mutexes (mutual exclusively locks), that is implemented toensure that no conflicts arise between multiple threads accessing shared.

In OCI,mutexes are granted for each environment handle.

         The thread safety feature of the Oracledatabase server and OCI libraries allows developers to use the OCI in amultithreaded environment. Thread safety ensures code can be reentrant, withmultiple threads making OCI calls without side effects.

The OCIThread Package

         The OCIThread package provides anumber of commonly used threading primitives. It offers a portable interface tothreading capabilities native to various operating systems, but does notimplement threading on operating system that do not have native threadingcapability.

         OCIThread does not provide a portableimplementation, but it serves as a set of portable covers for nativemultithreaded facilities. Therefore, operating systems that do not have nativesupport for multithreading will only be able to support a limitedimplementation of the OCIThread package. As a result, products that rely on allof OCIThread’s functionality will not port to all operating systems. Productsthat must port to all operating systems must use only subset of OCIThread’sfunctionality.

         The OCIThread API consists of threemain parts. Each part is described briefly here. The following subsectionsdescribe each in greater detail.

         ·Initialization and Termination. These calls deal with theinitialization and termination of OCIThread context, which is required forother OCIThread calls.

         OCIThread only requires that theprocess initialization function, OCIThreadProcessInit(), is called when OCIThreadis being used in a multithreaded application. Failing to callOCIThreadProcessInit() in a single-threaded application is not an error.

         Separate calls to OCIThreadInit() willall return the same OCIThread context. Each call to OCIThreadInit() musteventually be matched by a call to OCIThreadTerm().

         ·Passive Threading Primitives. Passivethreading primitives are used to manipulate mutual exclusion locks (mutex),thread IDs, and thread-specific data keys. These primitives are described aspassive because while their specifications allows for the existence of multiplethreads, they do not require it. It is possible for these primitives to beimplemented according to specification in both single-threaded andmultithreaded environments. As a result, OCIThread clients that use only theseprimitives will not require a multiple-thread environment in order to workcorrectly. They will be able to work in single-threaded environments withoutbranching code.

         ·Passive Threading Primitives. Active threading primitives dealwith the creation, termination, and manipulation of threads. These primitivesare described asactive because theycan only be used in true multithreaded environments. Their specificationexplicitly requires multiple threads. If you need to determine at runtimewhether or not you are in a multithreaded environment, call OCIThreadIsMulti()before using an OCIThread active primitives.

Initialization and Termination

         The types and functions describedin this section are associated with the initialization and termination of the OCIThreadpackage. OCIThread must be initialized before any of its functionality can beused.

         The observed behavior of theinitialization and termination functions is the same regardless of whetherOCIThread is in single-threaded or multithreaded environment. Table 9-1 listsfunctions for thread initialization and termination.

OCIThread Context

         Most calls to OCIThread functions usethe OCI environment or user session handle as a parameter. The OCIThreadcontext is part of the OCI environment or user session handle and it must beinitialized by calling OCIThreadInit(). Termination of the OCIThread contextoccurs by calling OCIThreadTerm().

         注意:The OCIThreadcontext is an opaque data structure. Do not attempt to examine the contents ofthe context.

Passive Threading Primitives

         The passive threading primitives dealwith the manipulation of mutex, thread ID’s, and thread-specific data. Sincethe specifications of these primitives do not require the existence of multiplethreads, they can be used both in multithreaded and single-threaded operatingsystems. Table 9-2 lists functions used to implement passive threading.

OCIThreadMutex

         The OCIThreadMutex datatype is used torepresent a mutex. This mutex is used to ensure that:

         ·only one thread accesses a givenset of data at a time, or

         ·only one threadexecutes a given critical section of code at a time

         Mutex pointers can be declared asparts of client structures or as stand-alone variables. Before they can beused, they must be initialized using OCIThreadMutexInit(). Once they are nolonger needed, they must be destroyed using OCIThreadMutexDestroy().

         A thread can acquire a mutex by usingOCIThreadMutexAcquire(). This ensures that only one thread at a time is allowedto hold a given mutex. A thread that holds a mutex can release it by calling OCIThreadMutexRelease().

OCIThreadKey

         The datatype OCIThreadKey can bethought of as a process-wide variable with a thread-specific value. This meansthat all threads in a process can use a given key, but each thread can examine ormodify the key independently of the other threads. The value that a thread seeswhen it examines the key will always be the same as the value that it last setfor the key. It will not see any values set for the key by other threads. Thedatatype of the value held by a key is a dvoid * generic pointer.

         Keys can be created usingOCIThreadKeyInit(). Key value are initialized to NULL for all threads.

         A thread can set a key’s value usingOCIThreadKeySet(). A thread can get a key’s value using OCIThreadKeyGet().

Connection Pooling in OCI

         Connection pooling is the use of agroup (the pool) of reusable physical connections by several sessions, in orderto balance loads. The management of the pool is done by OCI, not theapplication. Applications that can use connection pooling include middle-tierapplications for Web application servers and e-mail servers.

         A sample usage of this feature is in aWeb application server connected to a back-end Oracle database. Suppose that aWeb application server gets several concurrent requests for data from thedatabase server. The application can create a pool (or a set of pools) in eachenvironment during application initialization.

OCI Connection Pooling Concepts

         Oracle has several transactionmonitor capabilities such as the fine-grained (細顆粒的) management of database sessionsand connections. This is done by separating the notion of database sessions(user handles) from connections (server handles). Using these OCI calls forsession switching and session migration, it is possible for an applicationserver or transaction monitor to multiplex several sessions over fewer physicalconnections, thus achieving a high degree of scalability by pooling ofconnections and back-end Oracle server processes.

         The connection pool itself is normallyconfigured with a shared pool of physical connections, translating to aback-end server pool containing an identical number of dedicated serverprocesses.

         The number of physical connections isless than the number of database sessions in use by the application. The numberof physical connections and back-end server processes are also reduced by usingconnection pooling. Thus many more database sessions can be multiplexed.

OCI Calls for Connection Pooling

         The steps in using connectionpooling in your application are:

         ·Allocate the Pool Handle

         ·Create theConnection Pool

         ·Logon to theDatabase

         ·Deal with SGALimitations in Connection Pooling

         ·Logoff from theDatabase

         ·Destroy theConnection Pool

         ·Free the Pool Handle

1.       Allocate the Pool Handle

Connection pooling requires that the poolhandle OCI_HTYPE_CPOOL be allocated by

OCIHandleAlloc().Multiple pools can be created for a given environment handle.

         For a single connection pool, here isan allocation example:

         OCICPool *poolhp;

         OCIHandleAlloc((     dvoid*) envhp,         (dvoid**)&poolhp,          OCI_HTYPE_CPOOL,

                                               (size_t)0,                   (dvoid**)  0);

2.       Create the Connection Pool

The function OCIConnectionPoolCreate() initializesthe connection pool handle. It has these

INparameters:

         ·connMin,the minimum number of connections to be opened when the pool is created.

         ·connIncr, the incremental number ofconnections that can be opened when all the connections are busy and a callneeds a connection. This increment is used only when the total number of openconnections is less than the maximum number of connections that can be openedin that pool.

         ·connMax, the maximum number of connectionsthat can be opened in the pool. When the maximum number of connections are openin the pool, and all the connections are busy, if a call needs a connection, itwill wait till it gets one. However, if the OCI_ATTR_CONN_NOWAIT attribute isset for the pool, an error is returned.

         · A poolUsername, and poolPasswd, to allow user sessions to transparentlymigrate between connections in the pool.

         ·Inaddition, an attribute OCI_ATTR_CONN_TIMEOUT, can be set to time out theconnections in the pool. Connections idle for more than this time are terminatedperiodically, to maintain a optimum number of open connections. If this attributeis not set, then the connections are never timed out.

         All the preceding attributes can beconfigured dynamically. So the application has the flexibility of reading thecurrent load (number of open connections and number of busy connections) andtuning these attributes appropriately.

         If the pool attributes (connMax,connMin, connIncr) are to be changed dynamically, OCIConnectionPoolCreate()must be called with mode set to OCI_CPOOL_REINITIALIZE.

         The OUT parameters poolName and poolNameLenwill contain values to be used in subsequent OCIServerAttach() and OCILogon2()calls in place of the database name and the database name length arguments.

         There is no limit on the number ofpools that can be created by an application. Middle tier applications can takeadvantage of this feature and create multiple pools to connect to the sameserver or to different servers,

         Here is an example of this call:

         OCIConnectionPoolCreate((OCIEnv*)envhp,          

                                                        (OCIError*)errhp,            (OCICPool*) poolhp,

                                                        &poolName,    &poolNameLen,

                                                        (text*)database,   strlen(database),

                                                        (ub4)conMin,            (ub4)connMax,         (ub4)connIncr,

                                                        (text*)pooluser,       strlen(pooluser),

                                                        (text*)poolPasswd,          strlen(poolPasswd),

                                                        OCI_DEFAULT);

         Logonto the Database

         The application will need to log on tothe database for each thread, using one of the following interface.

         ·OCILogon2()

         This is the simplest interface. Usethis interface when you need a simple Connection Pool connection and do not needto alter any attributes of the session handle. This interface can also be usedto make proxy connections to the database.

         Here is an example using OCILogon2():

         for (i=0;  I < MAXTHREADS;  ++i)

         {

                   OCILogon2(envhp, errhp,&svchp[i], “hr”, 2, “hr”, 2 , poolName,

                                               poolNameLen,  OCI_LOGON2_CPOOL));

         }

         In order to use this interface to get aproxy connection, set the password parameter to NULL.

         ·OCISessionGet()

         This is the recommended interface. Itgives the user the additional option of using external authentication methods,such as certifications, distinguished name, and so on. OCISessionGet() is therecommended uniform function call to retrieve a session.

         Here is an example usingOCISessionGet():

         For(I = 0; i< MAXTHREADS;  ++i)

         {

                   OCISessionGet(envhp,  errhp, &svchp,  authp,

                                               (OraText*)poolName,

                                               Strlen(poolName),            NULL, 0, NULL, NULL, NULL,

                                               OCI_SESSGET_CPOOL);

         }

3.       

11.  OCI多線程開發

線程是存在于一個更大的程序中的輕量級的程序。線程共享同樣的代碼和資料段,但是

有它們自己的程式計數器,寄存器和棧。線程共享全局和靜态變量,互斥鎖機制用來管理一個應用程式中的多個線程對這些變量的通路。

11.1 實作線程安全Implementing ThreadSafety

         為了利用線程安全的優勢,應用程式必須運作在一個線程安全的thread-safe作業系統。應用程式通過使用OCIEnvNlsCreate()函數的OCI_THREADED模式來運作多線程環境。

所有後續的對OCIEnvNlsCreate()函數的調用也要使用OCI_THREADED模式。

如果一個應用程式時單線程的,不論作業系統是否為線程安全的thread-safe,應用程式調用OCIInitialize()或者OCIEnvNlsCreate()是必須使用OCI_DEFAULT。運作在OCI_THREADED模式下的單線程應用程式可能運作的效率低一些。

如果一個多線程應用程式運作在一個線程安全的作業系統下,OCI庫将會為應用程式管理互斥鎖。一個應用程式可以不用這個特點而維持其自己的互斥機制通過調用OCIEnvCreate()時,使mode參數為OCI_NO_MUTEX。

11.2 OCIThread包 Package

         OCIThread包提供了一些廣泛使用的線程原語。它對不同作業系統的線程能力提供了一個可移植的接口。

         OCIThread API有三部分構成。包括:

         ·初始化和終止Initialization和Termination。這些函數處理OCIThread上下文的初始化和終止,這是其他OCIThread調用所必須的。

    OCIThread隻需要在一個多線程環境中當OCITread被使用時,程序初始化函數OCIThreadProcessInit()函數被調用。

    調用OCIThreadInit函數會傳回同樣的OCIThread上下文。每調用一次OCIThreadInit()函數最後必須對應一個OCIThreadTerm()函數。

         ·被動線程原語Passive Threading Primitives。被動線程原語用來操作互斥鎖、線程ID、和線程相關資料鍵。由于它們允許多線程的存在,但并不需要多線程,是以稱其為被動的。有可能它們在單線程或者多線程環境中實作。是以僅僅使用這些原語的OCIThread客戶并不一定需要一個多線程環境。它們可以運作在單線程環境下。

         ·主動線程原語Active Threading Primitives。主動線程原語處理線程的建立、終止和操作。由于它們隻能在真正的多線程環境中使用,是以它們被稱為主動的。

11.3 初始化和終止Initialization andTermination

         這部分描述與OCIThread包的初始化和終止有關的類型和函數。在其功能被使用之前,OCIThread一定要被初始化。

         不論OCIThread是在單線程還是多線程環境下,初始化和終止函數的行為都是相同的。表9-1列出了線程初始化和終止的函數

         表9-1 初始化和終止多線程函數

11.3 OCIThread上下文

         大多數OCIThread函數使用OCI環境句柄或者使用者會話句柄作為一個參數。OCIThread上下文是OCI環境或者使用者會話句柄的一部分,必須調用OCIThreadInit()函數來将其初始化。通過調用OCIThreadTerm()函數來終止OCIThread上下文。

         注意:OCIThread上下文是一個不透明的資料結構。不要試圖檢視上下文中的内容。

11.4 被動線程原語

         表9-2列出了實作被動線程的函數

         表9-2 被動線程原語

11.4.1 OCIThreadMutex

         OCIThreadMutex資料類型用來代表一個互斥鎖。這個互斥鎖用來確定:

         ·在某一時刻隻有一個線程通路某一集合的資料

         ·在某一時刻隻有一個線程執行某一個臨界區

         互斥鎖指針可以被聲明為客戶資料結構的一部分或者一個單獨的變量。在它們可以被使用之前,必須使用OCIThreadMutexInit()函數來初始化它們。一旦不再需要它們,必須使用OCIThreadMutexDestroy()來銷毀它們。

         一個線程可以使用OCIThreadMutexAcquire()函數來擷取一個互斥鎖。這確定了在某一時刻隻有一個線程被允許持有互斥鎖。持有互斥鎖的線程可以通過調用OCIThreadMutexRelease()函數來釋放互斥鎖。

11.4.2 OCIThreadKey

         OCIThreadKey

12.  

轉載請注明