OCI編程高級篇(八) LOB寫操作
訪問www.tomcoding.com網(wǎng)站,學習Oracle內(nèi)部數(shù)據(jù)結(jié)構(gòu),詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術(shù)含量的內(nèi)容。
上一節(jié)我們介紹了LOB定位符的綁定和定義操作,這里重點強調(diào)一下定義操作,這個行為一般用于LOB SELECT操作,LOB SELECT操作是所有LOB操作的基礎(chǔ),所有的關(guān)于LOB操作的OCI函數(shù)都是針對LOB定位符的,LOB SELECT的目的就是為了得到一個LOB定位符,一個LOB表的每行數(shù)據(jù)的每個LOB字段都對應一個LOB定位符,所以處理一行數(shù)據(jù)的多個LOB字段也要得到多個LOB定位符。下面看看LOB寫操作的步驟。
1. 準備LOB SELECT語句,一般SQL語句文本為SELECT lob_column FROM lob_table WHERE XXXX=XXXX FOR UPDATE。
2. 定義輸出的LOB定位符。這個定位符在之前要分配好,不用設(shè)置為空LOB。
3. 執(zhí)行LOB SELECT語句。
4. 執(zhí)行OCIStmtFetch()操作,把LOB定位符和LOB字段關(guān)聯(lián)起來。
5. 打開LOB定位符,使用OCILobOpen()函數(shù)。
6. 寫入LOB數(shù)據(jù),可以循環(huán)寫入多次LOB數(shù)據(jù),使用OCILobWrite2()函數(shù)。
7. 關(guān)閉LOB定位符,使用OCILobClose()函數(shù)。
8. 提交數(shù)據(jù)庫改變。
先看看用到的OCI函數(shù)原型和參數(shù)。
打開LOB函數(shù)。
sword OCILobOpen ( OCISvcCtx *svchp,
OCIError *errhp,
OCILobLocator *locp,
ub1 mode );
svchp是一個輸入?yún)?shù),是OCI服務(wù)上下文句柄。
errhp是一個輸入/輸出參數(shù),錯誤句柄,用于返回錯誤碼和錯誤信息文本。
locp是一個輸入/輸出參數(shù),需要打開的LOB定位符。
mode是一個輸入?yún)?shù),打開的方式,取值OCI_LOB_READONLY或OCI_LOB_READWRITE。
關(guān)閉LOB函數(shù)。
sword OCILobClose ( OCISvcCtx *svchp,
OCIError *errhp,
OCILobLocator *locp );
svchp是一個輸入?yún)?shù),是OCI服務(wù)上下文句柄。
errhp是一個輸入/輸出參數(shù),錯誤句柄,用于返回錯誤碼和錯誤信息文本。
locp是一個輸入/輸出參數(shù),需要關(guān)閉的LOB定位符。
寫LOB函數(shù)。
sword OCILobWrite2 ( OCISvcCtx *svchp,
OCIError *errhp,
OCILobLocator *locp,
oraub8 *byte_amtp,
oraub8 *char_amtp,
oraub8 offset,
void *bufp,
oraub8 buflen,
ub1 piece,
void *ctxp,
OCICallbackLobWrite2 (cbfp)
(
void *ctxp,
void *bufp,
oraub8 *lenp,
ub1 *piecep
void **changed_bufpp,
oraub8 *changed_lenp
)
ub2 csid,
ub1 csfrm );
svchp是一個輸入/輸出參數(shù),是OCI服務(wù)上下文句柄。
errhp是一個輸入/輸出參數(shù),錯誤句柄,用于返回錯誤碼和錯誤信息文本。
locp是一個輸入/輸出參數(shù),需要操作的LOB定位符,唯一引用一個LOB。
byte_amtp是一個輸入/輸出參數(shù),寫入LOB的字節(jié)數(shù),在BLOB寫入時使用。
char_amtp是一個輸入/輸出參數(shù),寫入LOB的字符個數(shù),在CLOB寫入時使用,BLOB寫入時忽略這個參數(shù)。
offset是一個輸入?yún)?shù),寫入LOB的絕對偏移量,從LOB頭開始計算。對CLOB計算單位是字符,對BLOB計算單位是字節(jié)。offset的位置從1開始計算。如果使用流寫入方式,只需要在第一次調(diào)用寫函數(shù)時設(shè)置offset值,后續(xù)的寫函數(shù)可以忽略offset,函數(shù)會自動判斷。
bufp是一個輸入?yún)?shù),是寫入的LOB數(shù)據(jù)的緩沖區(qū)指針。
buflen是一個輸入?yún)?shù),表示LOB數(shù)據(jù)緩沖區(qū)中數(shù)據(jù)的大小,以字節(jié)計算。
piece是一個輸入?yún)?shù),表示寫入的是哪個數(shù)據(jù)片。取值為OCI_ONE_PIECE,流模式中為OCI_FIRST_PIECE,OCI_NEXT_PIECE和OCI_LAST_PIECE。
ctxp是一個輸入?yún)?shù),是回調(diào)函數(shù)的上下文指針,可以設(shè)置為NULL。
cbfp是一個輸入?yún)?shù),是回調(diào)函數(shù)的函數(shù)指針,不使用回調(diào)函數(shù)設(shè)置為NULL。
csid是一個輸入?yún)?shù),是緩沖區(qū)中數(shù)據(jù)的字符集ID,只對CLOB起作用。
csfrm是一個輸入?yún)?shù),是緩沖區(qū)數(shù)據(jù)的字符集形式,取值SQLCS_IMPLICIT表示與數(shù)據(jù)庫字符集一致,取值SQLCS_NCHAR表示使用國際字符集。
我們使用上一節(jié)中創(chuàng)建的表test_clob_tab,里面已經(jīng)插入一條空LOB數(shù)據(jù),現(xiàn)在看看怎樣寫入LOB數(shù)據(jù),我們向LOB中寫入20次,每次寫入4000字符,使用流模式寫入。代碼如下。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; ??int write_to_lob(void){ int i; sword rc; sb4 ec; ub1 piece; int slen; oraub8 amt; OCIDefine *defp; OCILobLocator *locp; char sqltxt[1024]; text errbuf[512]; char buf[4096]; /* 分配LOB定位符 */ rc = OCIDescriptorAlloc((const void *)envhp, (void **)&locp, OCI_DTYPE_LOB, 0, (void **)NULL); if (rc != OCI_SUCCESS) { OCIErrorGet(envhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDescriptorAlloc() - [%d] %s\n", ec, errbuf); return (-1); } /* 下面執(zhí)行LOB SELECT操作 */ strcpy(sqltxt, "SELECT MESSAGE FROM test_clob_tab WHERE ID=1 FOR UPDATE"); slen = strlen(sqltxt); rc = OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIStmtPrepare() - [%d] %s\n", ec, errbuf); return (-1); } /* 定義LOB定位符輸出 */ rc = OCIDefineByPos((OCIStmt *)smthp, (OCIDefine **)&defp, (OCIError *)errhp, (ub4)1, (void *)&locp, (sb4)sizeof(OCILobLocator *), (ub2)SQLT_CLOB, (void *)NULL, (ub2 *)NULL, (ub2 *)NULL, (ub4)OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDefineByPos() - [%d] %s\n", ec, errbuf); return (-1); } /* 執(zhí)行語句 */ rc = OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 0, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT); /* mode */ if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIExecute() - [%d] %s\n", ec, errbuf); return (-1); } /* 執(zhí)行fetch操作 */ rc = OCIStmtFetch(smthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIStmtFetch() - [%d] %s\n", ec, errbuf); return (-1); } /* 打開LOB */ rc = OCILobOpen(svchp, errhp, locp, OCI_LOB_READWRITE); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCILobOpen() - [%d] %s\n", ec, errbuf); return (-1); } for (i=0; i<20; i++) { if (i == 0) piece = OCI_FIRST_PIECE; else if (i == 19) piece = OCI_LAST_PIECE; else piece = OCI_NEXT_PIECE; sprintf(buf, "%02d", i); memset(&buf[2], 3998, 'A'); amt = 4000; rc = OCILobWrite2(svchp, errhp, locp, NULL, &amt, 1, buf, 4000, piece, 0, SQLCS_IMPLICIT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCILobWrite2() - [%d] %s\n", ec, errbuf); return (-1); } } /* 關(guān)閉LOB */ rc = OCILobClose(svchp, errhp, locp); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCILobClose() - [%d] %s\n", ec, errbuf); return (-1); } /* 提交改變 */ rc = OCITransCommit(svchp, errhp, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCITransCommit() - [%d] %s\n", ec, errbuf); return (-1); } /* 釋放LOB定位符 */ rc = OCIDescriptorFree((void *)locp, OCI_DTYPE_LOB); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDescriptorFree() - [%d] %s\n", ec, errbuf); return (-1); } return (0); }
在上面的寫入中使用了流模式,在第一次寫入時使用OCI_FIRST_PIECE,最后一次寫入使用OCI_LAST_PIECE,其他的寫入使用OCI_NEXT_PIECE,只需要在第一次寫入時指定寫入偏移量1,就可以從頭寫入數(shù)據(jù),后續(xù)寫操作的偏移量都被忽略了。寫入函數(shù)的csid設(shè)置為0,數(shù)據(jù)使用環(huán)境變量NLS_LANG定義的字符集。
如果不使用流模式寫入,那么寫入操作使用OCI_ONE_PIECE,每次寫入一片數(shù)據(jù),每次要自己計算偏移量的位置,好處是可以隨機向任意位置寫入數(shù)據(jù)。
在寫數(shù)據(jù)前要打開LOB,寫完后要關(guān)閉LOB,跟寫一個文件相似。如果不打開LOB也可以直接調(diào)用寫函數(shù),不過每次寫操作Oracle還是會隱式的打開LOB,寫完一次后隱式關(guān)閉LOB,這樣在大量多次寫入時會影響效率,所以在寫之前打開LOB是一個好習慣。

浙公網(wǎng)安備 33010602011771號