一. Oracle oci工具包安裝:
$ORACLE_HOME\BIN:執行檔案和help檔案
$ORACLE_HOME\OCI\INCLUDE:頭檔案
$ORACLE_HOME\OCI\LIB\BC: for Borlanf C++的OCI庫
$ORACLE_HOME\OCI\LIB\MSVC: for MS Visual C++的OCI庫 假如是unix下,對于ORACLE8i,則OCI庫在$ORACLE_HOME/lib下,假如是9i,則在$ORACLE_HOME/lib32下,庫檔案名一般為libclntsh.so
1. 建立OCI環境即建立和初始化OCI工作環境,其他的OCI函數需要OCI環境才能執行。
2. 需要申請的句柄類型:
OCI環境句柄: OCI_HTYPE_ENV—它定義所有OCI函數的環境調用環境,是其他句柄的父句柄。(由OCIEnvInit或OCIEnvCreate生成)
錯誤句柄:OCI_HTYPE_ERROR—作為一些OCI函數的參數,用來記錄這些OCI函數操作過程中所産生的錯誤,當有錯誤發生時,可用COIErrorGet()來讀取錯誤句柄 中記錄的錯誤資訊。
伺服器環境句柄:OCI_HTYPE_SVCCTX—定義OCI調用的伺服器操作環境,它包含伺服器、使用者會話和事務三種句柄。
伺服器句柄:OCI_HTYPE_SERVER—辨別資料源,它轉換為與伺服器的實體連接配接。
使用者會話句柄:OCI_HTYPE_ session —定義使用者角色和權限及OCI調用的執行環境。
事務句柄:OCI_HTYPE_TRANS—定義執行SQL操作的事務環境,事務環境中包含使用者的會話狀态資訊。
語句句柄:OCI_HTYPE_STMT—是一個辨別SQL語句或PL/SQL塊,以及其相關屬性的環境。
Bind/Define句柄:屬于語句句柄的子句柄,由OCI庫隐式自動生成。使用者不需要自己再申請,OCI輸入變量存儲在bind 句柄中,輸出變量存儲在定義句柄中 3. 句柄屬性包括:
伺服器環境句柄屬性:(OCI_HTYPE_SVCCTX)
OCI_ATTR_SERVER—設定/讀取服務環境的伺服器環境屬性
OCI_ATTR_SESSION—設定/讀取服務環境的會話認證環境屬性
OCI_ATTR_TRANS—設定/讀取服務環境的事務環境屬性
使用者會話句柄屬性:(OCI_HTYPE_SESSION)
OCI_ATTR_USERNAME—設定會話認證所使用的使用者名
OCI_ATTR_PASS Word —設定會話認證所使用的使用者密碼
伺服器句柄:(OCI_HTYPE_SEVER)
OCI_ATTR_NOBLOCKING_MODE—設定/讀取伺服器連接配接:=TRUE時伺服器連接配接設定為非阻塞方式
語句句柄:(OCI_HTYPE_STMT)
OCI_ATTR_ROW_COUNT—隻讀,為目前已處理的行數,其default=1
OCI_ATTR_STMT_TYPE—讀取目前SQL語句的類型:
Eg : OCI_STMT_BEGIN
OCI_STMT_SELECT
OCI_STMT_INSERT
OCI_STMT_UPDATE
OCI_STMT_DELETE
OCI_ATTR_PARAM_COUNT—傳回語句選擇清單中的列數
4. 關于輸出變量定義:假如在語句執行前就知道select語句的選擇清單結構,則定義輸出操作可在調用 OCISTMTExecute前進行,假如查詢語句的參數為使用者動态輸入的,則必須在執行後定義。
5. OCI函數傳回值:
OCI_SUCCESS –函數執行成功 (=0)
OCI_SUCCESS_WITH_INFO –執行成功,但有診斷消息傳回,可能是警告資訊
OCI_NO_DATA—函數執行完成,但沒有其他資料
OCI_ERROR—函數執行錯誤
OCI_INVALID_HANDLE—傳遞給函數的參數為無效句柄,或傳回的句柄無效
OCI_NEED_DATA—需要應用程式提供運作時刻的資料
OCI_CONTINUE—回調函數傳回代碼,說明回調函數需要OCI庫恢複其正常的處理操作
OCI_STILL_EXECUTING—服務環境建立在非阻塞模式,OCI函數調用正在執行中。
6. OCI連接配接有二種方式:Blocking(阻塞方式)和non_Blocking(非阻塞方式),阻塞方式就是當調用 OCI操作時,必須等到此OCI操作完成後伺服器才傳回用戶端相應的資訊,不管是成功還是失敗。非阻塞方式是當用戶端送出OCI操作給伺服器後,伺服器立即傳回OCI_STILL_EXECUTING資訊,而并不等待服務端的操作完成。
對于non-blocking方式,應用程式若收到一個OCI函數的傳回值為 OCI_STILL_EXECUTING時必須再次對每一個OCI函數的傳回值進行判定,判定其成功與否。
可通過設定伺服器屬性為OCI_ATTR_NONBLOCKING_MODE來實作。系統預設方式為阻塞模式.
7. OCI函數設定的模式有:
OCI_DEFUALT:使用OCI預設的環境
OCI_THREADED:線程環境下使用OCI
OCI_OBJECT:對象模式
OCI_SHARED:共享模式
OCI_EVENTS
OCI_NO_UCB
OCI_ENV_NO_MUTEX:非互斥通路模式
其中模式可以用邏輯運算符進行疊加,将函數設定成多多種模式:如mode=OCI_SHREADED OCI_OBJECT
8. 當應用程序與伺服器斷開連接配接時,程式沒有使用OCITransCommit()進行事務的送出,則所有活動的事務會自動復原。
9. OCI重定義資料類型
typedef unsigned char ub1;
typedef signed char sb1;
typedef unsigned short ub2;
typedef signed short sb2;
typedef unsigned int ub4;
typedef signed int sb4;
typedef ub4 duword;
typedef sb4 dsword;
typedef dsword dword; 10.
在SQL語句預備後,可以用OCIAttrSet(0設定該語句的類型屬性OCI_ATTR_STMT_TYPE,以後可讀取語句屬性,根據屬性分别進行處理。
11. 批量綁定輸入和定義輸出參數:将資料存入一個靜态資料組中。一次執行可以送出或讀取多行記錄值。
12. 結合占位符和訓示器變量:
占位符:在程式中,一些SQL語句需要在程式運作時才能确定它的語句資料,在設計時可用一個占位符來代替,當程式運作時,在它預備好語句後,必須為每個占位符指定一個變量,即将占位符與程式變量位址結合,執行時,Oracle就從這些變量中讀取資料,并将它們與SQL語句一起傳遞給Oracle伺服器執行。OCI結合占位符時,它将占位符與程式變量關聯起來,并同時要指出程式變量的資料類型和資料長度。
如:select * from test where name=:p1 and age>:p2 :p1和:p2為占位符 訓示器變量:由于在Oracle中,列值可以為NULL,但在C語言中沒有NULL值,為了能使OCI程式表達NULL列值,OCI函數答應程式為所執行語句中的結合變量同時關聯一個訓示符變量或訓示符變量數組,以說明所結合的占位符是否為NULL或所讀取的列值是否為NULL,以及所讀取的列值是否被截取。
除SQLT_NTY(SQL Named DataType)外,訓示符變量或訓示符變量數組的資料類型為sb2,其值說明:
作為輸入變量時:(如insert ,update語句中)
=-1:OCI程式将NULL賦給Oracle表的列,忽略占位符結合的程式變量值
>=0:應用程式将程式變量值賦給指定列
作為輸出變量時:(如select語句中)
=-2:所讀取的列資料長度大于程式變量的長度,則被截取。
=-1:所讀取的值為NULL,輸出變量的值不會被改變。
=0:資料被完整讀入到指定的程式變量中
>0:所讀取的列資料長度大于程式變量的長度,則被截取,訓示符變量值為所讀取資料被截取前的實際長度
三. OCI函數說明
注:紅色為輸入參數 藍色為輸出參數 ,否則為輸入/出參數 示例以下面結構作為說明
sword swResult;
OCIBind* hBind;
OCIDefine* hDefine;
OCIStmt *stmtp
OCIError *errhp;
OCIStmt *stmtp
OCISvcCtx * svchp
OCIEnv * envhpp;
OCISession * usrhp;
sb2 sb2aInd[30]; //訓示器變量,用于取可能存在空值的字段
Typedef strcut
{
char tname[40];
int age;
} t_std;
typedef struct
{
sb2 sb2_tname[100];
sb2 sb2_age[100];
} stdInd_T; //訓示器數組
typedef struct
{
ub2 ub2_tname[100];
ub2 ub2_age[100];
} stdLen_T; //字段長度 t_std tstd[100]; //數組變量,用于批量操作
stdInd_T tstdInd;
stdLen_T tstdLen;
stdLen_T tstdRet; t_std std; 各函數數明
1.建立OCI環境
sword OCIEnvCreate(
OCIEnv **envhpp, //OCI環境句柄指針
ub4 mode, //初始化模式:OCI_DEFAULT/OCI_THREADED 等
CONST dvoid *ctXP,
CONST dvoid *(*malicfp)(dvoid *ctxp,size_t size),
CONST dvoid *(ralocfp)(dvoid *ctxp,dvoid *memptr,size_t newsize),
CONST void *(*mfreefp)(dvoid *ctxp,dvoid *memptr),
Size_t xstramemsz,
Dvoid **usrmempp
)
eg :
swResult = OCIEnvCreate(&envhpp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCIInitialize (
ub4 mode,
CONST dvoid *ctxp,
CONST dvoid *(*malocfp) (),
CONST dvoid *(*ralocfp) (),
CONST void (*mfreefp) ()
);
sword OCIEnvInit (
OCIEnv **envhpp,
ub4 mode,
size_t xtramemsz,
dvoid **usrmempp
);
注:
在8i以後,可用OCIEnvCreate一個函數就可以初始化環境了,相當于OCIInitialize+ OCIEnvInit 2.申請/釋放句柄
sword OCIHandleAlloc(
CONST dvoid *parenth, //新申請句柄的父句柄,一般為OCI環境句柄
Dvoid **hndlpp, //申請的新句柄
Ub4 type, type, //句柄類型
Size_t xtramem_sz, //申請的記憶體數
Dvoid **usrmempp //申請到的記憶體塊指針
)
注:
一般需要申請的句柄有:
伺服器句柄OCIServer, 句柄類型OCI_HTYPE_SERVER
錯誤句柄OCIError,用于捕捉OCI錯誤資訊, 句柄類型OCI_HTYPE_ERROR
事務句柄OCISession, 句柄類型OCI_HTYPE_SESSION
上下文句柄OCISvcCtx, 句柄類型OCI_HTYPE_SVCCTX
SQL語句句柄OCIStmt, 句柄類型OCI_HTYPE_STMT
eg: 申請一個錯誤句柄OCIError
swResult = OCIHandleAlloc(envhpp, (dvoid *)& errhp, OCI_HTYPE_ERROR, 0, NULL);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
{
return FALSE;
}
釋放句柄
sword OCIHandleFree(
dvoid *hndlp, //要釋放的句柄
ub4 type //句柄類型
)
eg:
OCIHandleFree(stmtp, OCI_HTYPE_STMT)
3.讀取/設定句柄屬性
sword OCIAttrSet(
dvoid *trgthndlp, //需設定的句柄名
ub4 trghndltyp, //句柄類型
dvoid *attributep, //設定的屬性名
ub4 size, //屬性值長度
ub4 attrtype, //屬性類型
OCIError *errhp //錯誤句柄
)
注:一般要設定的屬性有:
伺服器執行個體:
句柄類型OCI_HTYPE_SVCCTX,屬性類型OCI_ATTR_SERVER
連接配接資料的使用者名:
句柄類型OCI_HTYPE_SESSION,屬性類型OCI_ATTR_USERNAME
使用者密碼
句柄類型OCI_HTYPE_SESSION,屬性類型OCI_ATTR_PASSWORD
事務:
句柄類型OCI_HTYPE_SVCCTX,屬性類型OCI_ATTR_SESSION
eg:設定使用者名和密碼
char username[20],passwd[20];
strcpy(username,”tiger”)
strcpy(passwd,”cotton”)
swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*) username, strlen(username),
OCI_ATTR_USERNAME, errhp);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE; swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*) passwd, strlen(passwd),
OCI_ATTR_PASSWORD, errhp);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCIAttrGet(
dvoid *trgthndlp, //需讀取的句柄名
ub4 trghndltyp, //句柄類型
dvoid *attributep, //讀取的屬性名
ub4 *sizep, //屬性值長度
ub4 attrtype, //屬性類型
OCIError *errhp //錯誤句柄
) 4.連接配接/斷開伺服器
多使用者方式連接配接:
sword OCIServerAttach(
OCIServer *srvhp,//未初始化的伺服器句柄
OCIError *errhp,
CONST text *dblink,//伺服器SID
sb4 dblink_len,
ub4 mode //=OCI_DEFAULT,系統環境将設為阻塞方式
); sword OCIServerDetach (
OCIServer *srvhp,
OCIError *errhp,
ub4 mode //OCI_DEFAULT
);
單使用者方式連接配接:
sword OCILogon (
OCIEnv *envhp,
OCIError *errhp,
OCISvcCtx **svchp,
CONST text *username,
ub4 uname_len,
CONST text *password,
ub4 passwd_len,
CONST text *dbname,
ub4 dbname_len
);
sword OCILogoff (
OCISvcCtx *svchp
OCIError *errhp
); 5.開始/結束一個會話
先認證使用者再建立一個會話連接配接
sword OCISessionBegin (
OCISvcCtx *svchp, //服務環境句柄
OCIError *errhp,
OCISession *usrhp, //使用者會話句柄
ub4 credt, //認證類型
ub4 mode //操作模式
); *認證類型:
OCI_CRED_RDBMS:用 資料庫 使用者名和密碼進行認證,則先要設定OCI_ATTR_USERNAME和OCI_ATTR_PASSWORD屬性
OCI_CRED_EXT:外部認證,不需要設定使用者和密碼
OCI_DEFAULT:使用者會話環境隻能被指定的伺服器環境句柄所設定
OCI_SYSDBA:使用者要具有sysdba權限
OCI_SYSOPER:使用者要具有sysoper權限
Eg:
swResult = OCISessionBegin(svchp, errh,usrhp, OCI_CRED_RDBMS, OCI_DEFAULT);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCISessionEnd (
OCISvcCtx *svchp,
OCIError *errhp,
OCISession *usrhp,
ub4 mode );
6.讀取錯誤資訊
sword OCIErrorGet (
dvoid *hndlp, //錯誤句柄
ub4 recordno,//從那裡讀取錯誤記錄,從1開始
text *sqlstate,//已取消,=NULL
sb4 *errcodep, //錯誤号
text *bufp, //錯誤内容
ub4 bufsiz, //bufp長度
ub4 type //傳遞的錯誤句柄類型
=OCI_HTYPE_ERROR:錯誤句柄
=OCI_HTYPE_ENV:環境句柄
);
eg:
ub4 ub4RecordNo = 1;
OCIError* hError
sb4 sb4ErrorCode;
char sErrorMsg[1024];
if (OCIErrorGet(hError, ub4RecordNo++, NULL, &sb4ErrorCode, (OraText*) sErrorMsg, sizeof(sErrorMsg), OCI_HTYPE_ERROR) == OCI_SUCCESS)
PR intf(“error msg:%s\n”, sErrorMsg);
7.預備SQL語句
sword OCIStmtPrepare (
OCIStmt *stmtp,//語句句柄
OCIError *errhp,
CONST text *stmt, //SQL語句
ub4 stmt_len, //語句長度
ub4 language, //語句的文法格式=OCI_NTV_SYNTAX
ub4 mode //=OCI_DEFAULT
); eg:
char sSQL[1024]; sprintf(sSQL, “select table_name from user_tables”); swResult = OCIStmtPrepare(stmtp errhp, (CONST OraText*)sSQL, strlen(sSQL), OCI_NTV_SYNTAX, OCI_DEFAULT);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
8. 綁定輸入參數 OCIBindArrayOfStruct() Set sk ip parameters for static array bind ,數組綁定,一般用于批量操作
OCIBindByName() Bind by name 按名綁定
OCIBindByPos() Bind by position 按位置綁定,建議一般按此方式綁定
OCIBindDynamic() Sets additional attributes after bind with OCI_DATA_AT_EXEC mode
OCIBindObject() Set additional attributes for bind of named data type 注:
OCIBindArrayOfStruct必須先用OCIBindByPos初始化,然後在OCIBindArrayOfStruct中定義每個參數所跳過的位元組數。
如: 存儲方式: 第一條記錄第二條記錄 N
SkipPara(實際就是結構體長度,即本次所有列的長度和) sword OCIBindByName (
OCIStmt *stmtp, //語句句柄
OCIBind **bindpp,//結合句柄,=NULL
OCIError *errhp,
CONST text *placeholder,//占位符名稱
sb4 placeh_len, //占位符長度
dvoid *valuep, //綁定的變量名
sb4 value_sz, //綁定的變量名長度
ub2 dty, //綁定的類型
dvoid *indp, //訓示符變量指針(sb2類型),單條綁定時為NULL,
ub2 *alenp, //說明執行前後被結合的數組變量中各元素資料實際的長度,單條綁定時為NULL
ub2 *rcodep,//列級傳回碼資料指針,單條綁定時為NULL
ub4 maxarr_len, //最多的記錄數,假如是單條綁定,則為0
ub4 *curelep, //實際的記錄數,單條綁定則為NULL
ub4 mode //=OCI_DEFAULT
);
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 ); sword OCIBindArrayOfStruct (
OCIBind *bindp,//綁定的結構句柄,由OCIBindByPos定義
OCIError *errhp,
ub4 pvskip, //下一列跳過的位元組數**
ub4 indskip,//下一個訓示器或數組跳過的位元組數
ub4 alskip, //下一個實際值跳過的位元組數
ub4 rcskip //下一個列級傳回值跳過的位元組數
);
例:
sword swResult;
OCIBind* hBind;
Ub4 rec_num;
Sql: insert into student values (:p1,:p2) 單條綁定:
hBind = NULL;
swResult = OCIBindByPos(stmtp &hBind, errhp,1,ststd.tname,
sizeof(ststd.tname), SQLT_CHR, NULL,
NULL,NULL,0, NULL, OCI_DEFAULT);
批量取資料,一次取100條
Sql: select username,age from student where username=:p1 and age=:p2 hBind = NULL;
swResult = OCIBindByPos(stmtp &hBind, errhp,1,tstd[0].tname,
sizeof(tstd[0].tname), SQLT_CHR, &tstdInd.sb2_usernmae[0],
&tstdLen.ub2_username[0],&tstdRet.ub2_username[0],100, &rec_num, OCI_DEFAULT);
swResult = OCIBindArrayOfStruct(hBind, errhp,sizeof(tstd [0]), sizeof(sb2), sizeof(ub2), sizeof(ub2)); 9.執行SQL語句
sword OCIStmtExecute (
OCISvcCtx *svchp, //服務環境句柄
OCIStmt *stmtp, //語句句柄
OCIError *errhp,
ub4 iters, // **
ub4 rowoff, /) ); sword OCIDefineObject ( OCIDefine *defnp,
OCIError *errhp,
CONST OCIType *type,
dvoid **pgvpp,
ub4 *pvszsp,
dvoid **indpp,
ub4 *indszp );
eg:
單條查詢
sql: select username,age from student where username=:p1;
假如此字段有可能有空值,則
hDefine = NULL;
swResult = OCIDefineByPos(stmtp &hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, & sb2aInd[0], NULL, NULL, OCI_DEFAULT);
假如此字段沒有空值,則
hDefine = NULL;
swResult = OCIDefineByPos(stmtp &hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT); 批量查詢
select username,age from student where age>30;
hDefine = NULL;
swResult = OCIDefineByPos(stmtp, &hDefine, errhp, 1, &tstd[0].username,
sizeof(tstd[0].usenmae), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT); swResult = OCIDefineArrayOfStruct(hDefine, errhp, sizeof(tstd[0]), 0, 0, 0);
11.提取結果
sword OCIStmtFetch (
OCIStmt *stmtp,//語句句柄
OCIError *errhp,
ub4 nrows, //從目前位置處開始一次提取的記錄數,對于資料變量,可以>1,否則不能>1
ub2 orientation,//提取的方向:OCI_FETCH_NEXT
ub4 mode //OCI_DEFAULT
) eg
while ((swResult=OCIStmtFetch stmtp errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT)) != OCI_NO_DATA)
{
……
} 12.事務操作
開始一個事務
sword OCITransStart (
OCISvcCtx *svchp,
OCIError *errhp,
uword timeout, //**
ub4 flags );
**注:
1. Timeout:
當flag=OCI_TRANS_RESUME:它表示還有多少秒事務将被激活
=OCI_TRANS_NEW: 事務響應的逾時時間(秒)
2. Flags:指定一個新的事務還是已有事務
=OCI_TRANS_NEW:定義一個新的事務
=OCI_TRANS_RESUME 預備一個事務:
sword OCITransPrepare (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT
sword OCITransForget (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT 斷開一個事務:
sword OCITransDetach (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT 送出一個事務:
sword OCITransCommit (
OCISvcCtx *svchp, //服務環境句柄
OCIError *errhp,
ub4 flags ); //OCI_DEFAULT
復原一個事務
sword OCITransRollback (
dvoid *svchp,
OCIError *errhp,
ub4 flags ); //OCI_DEFAULT
四. OCI資料類型與C語言資料類型對照表
表字段類型 OCI類型 C類型 備注
Number(N) SQLT_UIN int 無符号整型
Number(N) SQLT_INT int 有符号整型
Number(n,m) SQLT_FLT float 符點數
Varchar2(N) Sqlt_chr Char 字元串
Raw(N) Sqlt_BIN 具體看不同的定義 二進制類型,多用于一個結構字段
DATE SQLT_DAT 無 最好轉換成字元串或數字