OCI編程高級篇(一) 數組插入
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
在前面我們介紹了向數據庫表中插入數據的方法,在例子中一次插入一條數據,對于處理大量數據的場景這種方式顯然效率低下。幸運的是OCI提供了讓我們批量插入大量數據的方法,這就是數組插入。
數組插入的步驟與單條插入時基本一樣,只是在綁定占位符時,輸入的是一個數組地址,而不是一個單獨的變量地址,indp,alenp,rcodep也都指向一個數組。調用完OCIBindByPos()函數后,還要調用一個OCIBindArrayOfStruct()函數,這個函數定義每個變量跳過的字節個數,以便從開始能找到后續變量的地址。函數原型和參數如下。
sword OCIBindArrayOfStruct ( OCIBind *bindp,
OCIError *errhp,
ub4 pvskip,
ub4 indskip,
ub4 alskip,
ub4 rcskip );
bindp是一個輸入/輸出參數,是一個綁定句柄,由前一個函數OCIBindByPos()隱式分配得來。
errhp是一個輸入/輸出參數,是個錯誤句柄,用于獲取錯誤碼和錯誤信息文本。
pvskip是一個輸入參數,是綁定的數據數組值要跳過的字節數。
indskip是一個輸入參數,是指示變量要跳過的字節數。
alskip是一個輸入參數,是實際的數據長度跳過的字節數。
rcskip是一個輸入參數,是字段級出錯返回碼跳過的字節數。
下面來看看這個函數的用法,還是舉一個例子來說明,先看一下我們前面創建的test_tab表,表結構如下。CREATE TABLE test_tab (ID NUMBER, NAME CHAR(30), ADD VARCHAR2(200))。假如我們只向表中插入ID字段的數據,插入10條記錄,我們先定義一個整數數組int id[10],用于存放插入的數據,然后定義三個數組sb2 ind_id[10],ub2 alen_id[10],ub2 rcode_id[10]分別用于指示變量,實際長度和返回碼。我們先來看一下OCIBindArrayOfStruct()函數中跳過參數的取值,先看插入的數值,id[0]的地址與數組首地址id是一樣的,id[1]的地址是id+sizeof(int),id[2]的地址是id+2*sizeof(int),可以看到每個元素相對于前一個元素跳過的字節數是sizeof(int),就是pvskip的值。再看指示變量,ind_id[0]的地址與數組首地址ind_id一樣,ind_id[1]的地址是ind_id+sizeof(sb2),當前元素相對與前一個元素跳過的字節數是sizeof(sb2),就是indskip的值。同樣我們可以判斷alskip和rcskip的值。
下面我們看一個完整的例子,用數組在test_tab表中插入10條數據。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; /* 數組插入10條數據 */ int insert_array(void){ int i; sword rc; int slen; 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]; /* 分配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語句,這里iters要賦值為10,表示插入數組中的10條記錄 */ if (check_oci_error(errhp, OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 10, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 提交改變的數據 */ if (check_oci_error(errhp, OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0) return (-1); return (0); }
要注意的是在OCIStmtExecute()函數中iters的值要輸入10,才能插入數組中的10條數據,如果寫成1,雖然數組中有10條記錄,也只能插入1條。

浙公網安備 33010602011771號