OCI編程高級篇(四) 分片插入
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
當插入表中的一個字段,數據量比較大時怎么處理呢?我們在前面介紹OCIBindByPos()函數時看到,指示數據實際長度的參數alenp是一個ub2類型的整數,也就是說,綁定的數據量最大只有16K字節。當然大部分的字段長度都達不到這么大,但有兩個特殊類型LONG和LONG RAW字段的長度最大可以存儲2G的數據,如果向這樣的字段中插入超過16K的數據,還有沒有辦法呢?OCI提供了一種叫做分片操作的方法,可以應對這種狀況。分片操作顧名思義就是把大的數據分割成小的數據片,一片接一片的插入字段中。
要使用OCI的分片操作,首先在字段變量綁定時要用到OCI_DATA_AT_EXEC模式,就是在運行時提供數據,這里的綁定操作不關聯具體的變量。操作步驟如下。
1. 分配OCI語句句柄。
2. 準備SQL語句文本,分析語法。
3. 綁定占位符變量,OCIBindByPos()使用OCI_DATA_AT_EXEC模式。
4. 執行語句,OCIStmtExecute(),這次不會插入任何數據,返回碼OCI_NEED_DATA。
5. 提供數據,調用OCIStmtSetPieceInfo()函數,設置數據緩沖區地址和數據大小,指示分片的類型,第一片為OCI_FIRST_PIECE,下一片為OCI_NEXT_PIECE,最后一片為OCI_LAST_PIECE。
6. 執行語句,調用OCIStmtExecute()函數,這次會真正的插入數據片,如果上一步分片數據為OCI_LAST_PIECE,那么執行后返回碼為OCI_SUCCESS,程序插入數據完畢。否則返回碼為OCI_NEED_DATA,需要返回第五步,設置下一片數據地址和長度,繼續這一步的執行操作,直到最后一片數據,退出循環。
這里用到一個函數OCIStmtSetPieceInfo(),設置數據片信息函數,看一下它的原型和參數。
sword OCIStmtSetPieceInfo ( void *hndlp,
ub4 type,
OCIError *errhp,
const void *bufp,
ub4 *alenp,
ub1 piece,
const void *indp,
ub2 *rcodep );
hndlp是一個輸入/輸出參數,要設置信息的句柄。可以是綁定句柄,也可以是定義句柄。查詢的分片操作也要用到這個函數。
type是一個輸入參數,是上面句柄的類型,OCI_HTYPE_BIND或者OCI_HTYPE_DEFINE。
errhp是一個輸出參數,錯誤句柄,用于返回函數的錯誤碼和錯誤信息文本。
bufp是一個輸入/輸出參數,數據緩沖區地址,綁定句柄是提供數據的地址,定義句柄是接收數據的地址。
alenp是一個輸入/輸出參數,數據的實際長度,綁定句柄是提供數據的長度,定義句柄是返回數據的長度。
indp是一個輸入/輸出參數,是指示變量,與OCIBindByPos()函數中一樣。
rcodep是一個輸入/輸出參數,是字段級返回碼,與OCIBindByPos()函數中一樣。
假如我們創建一張表叫test_long_tab,然后向表中插入數據。建表語句為CREATE TABLE test_long_tab (ID NUMBER, NAME VARCHAR2(100), INFO LONG)。
我們下面看一個完整的例子,向LONG字段INFO中分片插入數據,一次數據片插入4000字符,插入10次。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; /* 插入分片的LONG數據 */ int insert_long_piece(void){ sword rc; int slen; sb2 ind_info; ub4 alen_info; ub2 rcode_info; ub1 piece; OCIBind *bndp; char sqltxt[1024]; char long_buf[4096]; /* 分配OCI語句句柄 */ rc = OCIHandleAlloc( (void *)envhp, (void **)&smthp, OCI_HTYPE_STMT, 0, (void **)NULL ); if (rc != OCI_SUCCESS) { fprintf(stderr, "OCIHandleAlloc() - allocate statement handle error !\n"); return (-1); } /* 生成SQL語句文本 */ strcpy(sqltxt, "INSERT INTO test_long_tab (ID, NAME, INFO) VALUES (1, 'LONG DATA', :1)"); slen = strlen(sqltxt); /* 準備語句 */ if (check_oci_error(errhp, OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0) return (-1); /* 綁定第一個占位符INFO,使用OCI_DATA_AT_EXEC模式,value_sz要設置成插入數據的最大值 */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)1, /* position */ (void *)NULL, /* valuep */ (sb4)40000, /* value_sz */ (ub2)SQLT_LNG, /* dty */ (void *)NULL, /* indp */ (ub2 *)NULL, /* alenp */ (ub2 *)NULL, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DATA_AT_EXEC) ) < 0) return (-1); for (i=0; ; i++) { /* 執行OCI語句 */ if ((rc = check_oci_error(errhp, OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 1, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT) /* mode */ )) < 0) return (-1); if (rc == OCI_SUCCESS) { /* 插入數據片完畢,退出循環 */ break; } if (rc != OCI_NEED_DATA) { fprintf(stderr, "data not completed !\n"); return (-1); } /* 設置數據片類型 */ if (i == 0) piece = OCI_FIRST_PIECE; else if (i == 9) piece = OCI_LAST_PIECE; else piece = OCI_NEXT_PIECE; /* 產生插入的數據,設置緩沖區和數據長度 */ sprintf(long_buf, "%d", i); memset(&long_buf[1], 'a', 3999); alen_info = 4000; if (check_oci_error(errhp, OCIStmtSetPieceInfo((void *)bndp, OCI_HTYPE_BIND, errhp, (const void *)long_buf, &alen_info, piece, (const void *)&ind_info, &rcode_info) ) < 0) return (-1); } /* 提交改變的數據 */ if (check_oci_error(errhp, OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0) return (-1); return (0); }

浙公網安備 33010602011771號