OCI編程高級篇(三) 批量執行
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
前面我們討論了數組插入數據的過程,實際上Oracle還是一條條的執行數組中的元素,只不過是一次性的提供了多條數據而已。當數據單條執行時,如果出現了錯誤,我們確切的知道是那一條出了錯,修改數據后再執行就可以了。但是數組插入讓我們遇到了問題,數組中的數據只要有一條出現了錯誤,整個數組插入操作就會報錯,并且錯誤行后面的數據不會再執行,這時只能先回滾掉所有的操作,然后找出錯誤數據行,修正后,再重新執行數組操作。如果數組中有多條錯誤,那會嚴重影響效率,并且程序員處理這些錯誤也會非常頭痛。
那么有沒有什么好的方法來避免上面的麻煩呢?答案是肯定的,OCI提供了一種機制,叫做執行的批量錯誤模式,在這一模式下,OCI會執行數組中的每一條數據,然后收集錯誤行的信息,OCI程序可以返回每個錯誤行的出錯信息,然后修正數據,只需要重新執行錯誤行數據就可以了。
批量錯誤模式的處理步驟如下。
1. 分配OCI語句。
2. 準備SQL語句文本。
3. 綁定數組數據。
4. 執行語句,使用OCI_BATCH_ERRORS模式。
5. 獲取出錯行的數量,使用OCI_ATTR_NUM_DML_ERRORS調用OCIAttrGet()函數。
6. 獲取每個錯誤的錯誤碼和錯誤信息文本
7. 處理錯誤。
在第六步中用到了一個函數OCIParamGet()用于取得每個錯誤的錯誤句柄。
sword OCIParamGet ( const void *hndlp,
ub4 htype,
OCIError *errhp,
void **parmdpp,
ub4 pos );
hndlp是一個輸入參數,是要獲取參數的句柄,我們在這里使用錯誤句柄。
htype是一個輸入參數,是句柄的類型,這里是OCI_HTYPE_ERROR。
errhp是一個輸入/輸出參數,是一個錯誤句柄,用于OCIErrorGet()取回錯誤信息。
parmdpp是一個輸出參數,參數值,在這里我們要取回一個錯誤句柄。
pos是一個輸入參數,這里是錯誤的位置號,從0開始。
還是用前面數組插入的例子,看看用OCI_BATCH_ERRORS模式怎樣處理錯誤。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; OCIError *errhp1 = NULL; OCIError *errhp2 = NULL; /* 數組插入10條數據 */ int insert_array_batch(void){ int i; sword rc; int slen; ub4 num_errs; ub4 row_off; sb4 ecode; sb2 ind_id[10]; sb2 ind_name[10]; sb2 ind_addr[10]; ub2 alen_id[10]; ub2 alen_name[10]; ub2 alen_addr[10]; ub2 rcode_id[10]; ub2 rcode_name[10]; ub2 rcode_addr[10]; int32_t id[10]; char name[10][32]; char addr[10][256]; OCIBind *bndp; char sqltxt[1024]; char errmsg1[16384]; /* 分配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_tab (ID, NAME, ADDR) VALUES (:1, :2, :3)"); slen = strlen(sqltxt); /* 準備語句 */ if (check_oci_error(errhp, OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0) return (-1); /* 綁定第一個占位符ID,綁定數組地址 */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)1, /* position */ (void *)id, /* valuep */ (sb4)4, /* value_sz */ (ub2)SQLT_INT, /* dty */ (void *)ind_id, /* indp */ (ub2 *)alen_id, /* alenp */ (ub2 *)rcode_id, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定綁定參數跳過的字節數 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, sizeof(int32_t), sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 綁定第二個占位符NAME */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)2, /* position */ (void *)name, /* valuep */ (sb4)30, /* value_sz */ (ub2)SQLT_STR, /* dty */ (void *)ind_name, /* indp */ (ub2 *)alen_name, /* alenp */ (ub2 *)rcode_name, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定綁定參數跳過的字節數,name定義的長度為32 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, 32, sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 綁定第三個占位符ADDR */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)3, /* position */ (void *)addr, /* valuep */ (sb4)200, /* value_sz */ (ub2)SQLT_STR, /* dty */ (void *)ind_addr, /* indp */ (ub2 *)alen_addr, /* alenp */ (ub2 *)rcode_addr, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定綁定參數跳過的字節數,addr定義的長度為256 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, 256, sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 賦值綁定的變量數據 */ for (i=0; i<10; i++) { id[i] = i+10; memset(name[i], 'a', 10); memset(addr[i], 'b', 20); name[i][10] = '\0'; addr[i][20] = '\0'; /* 指示符賦值為0,插入非NULL數據 */ ind_id[i] = 0; ind_name[i] = 0; ind_addr[i] = 0; /* 賦值變量的真實數據長度 */ alen_id[i] = sizeof(int32_t); alen_name[i] = strlen(name[i]) + 1; alen_addr[i] = strlen(addr[i]) + 1; } /* 執行OCI語句,注意這里要用OCI_BATCH_ERRORS模式 */ if (check_oci_error(errhp, OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 10, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_BATCH_ERRORS) /* mode */ ) < 0) return (-1); /* 分配錯誤句柄errhp1,用于取回錯誤條數 */ if (check_oci_error(errhp, OCIHandleAlloc((const void *)envhp, (void **)&errhp1, OCI_HTYPE_ERROR, 0, (void **)NULL)) < 0) return (-1); if (check_oci_error(errhp, OCIAttrGet (smthp, OCI_HTYPE_STMT, &num_errs, 0, OCI_ATTR_NUM_DML_ERRORS, errhp1)) < 0) return (-1); if (num_errs) { /* 分配錯誤句柄errhp2 */ if (check_oci_error(errhp, OCIHandleAlloc((const void *)envhp, (void **)&errhp2, OCI_HTYPE_ERROR, 0, (void **)NULL)) < 0) return (-1); for (i=0; i<num_errs; i++) { if (check_oci_error(errhp, OCIParamGet(errhp, OCI_HTYPE_ERROR, errhp1, &errhp2, i)) < 0) return (-1); if (check_oci_error(errhp, OCIAttrGet (errhp2, OCI_HTYPE_ERROR, &row_off, 0, OCI_ATTR_DML_ROW_OFFSET, errhp1)) < 0) return (-1); OCIErrorGet(errhp2, 1, NULL, &ecode, (OraText *)errmsg1, 16383, OCI_HTYPE_ERROR); fprintf(stderr, "row[%d] error: %d-%s\n", row_off, ecode, errmsg1); fprintf(stderr, "ID=%d, NAME=%s, ADDR=%s\n", id[row_off], name[row_off], addr[row_off]); } } /* 提交改變的數據 */ if (check_oci_error(errhp, OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0) return (-1); return (0); }

浙公網安備 33010602011771號