OCI編程高級篇(二) 數組查詢
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
在前面的章節介紹數據查詢時,也是一條條的從結果集中返回數據,大數據量查詢仍然是個瓶頸,好在OCI也提供了批量數據查詢返回結果的處理方法。數組查詢就是為解決這個問題誕生的,它允許一次OCIStmtFetch()操作,返回多行數據。數組查詢的步驟跟單條查詢時區別不大,只是在定義輸出時,輸出變量是數組地址,同樣在OCIDefineByPos()函數后面,要調用OCIDefineArryOfStruct()函數,用于指定數組每個元素跳過的字節數。先看一下原型和參數。
sword OCIDefineArrayOfStruct ( OCIDefine *defnp,
OCIError *errhp,
ub4 pvskip,
ub4 indskip,
ub4 rlskip,
ub4 rcskip );
跟上一節中OCIBindArrayOfStruct()函數差不多,只是第一個參數變成了定義句柄。
defnp是一個輸入/輸出參數,定義句柄,OCIDefineByPos()函數隱式分配返回的句柄。
errhp是一個輸入/輸出參數,錯誤句柄,用于返回錯誤碼和錯誤信息文本。
pvskip是一個輸入參數,輸出數組中前一個元素與后一個元素需要跳過的字節數。
indskip是一個輸入參數,指示變量數組要跳過的字節數。
rlskip是一個輸入參數,返回數據的實際長度數組要跳過的字節數。
rcskip是一個輸入參數,字段級返回碼數組要跳過的字節數。
還是以test_tab表為例,從表中查詢數據,使用數組返回查詢結果。與數組插入邏輯差不多,想必你也能很快寫出代碼,但是這里有個問題,插入數據時,我們確切知道插入的條數,可是查詢數據時我們卻不知道返回的條數,當數據條數不夠填滿數組時,我們怎么處理呢?要想辦法知道每次Fetch之后,帶回了多少條數據,還好OCI提供了一種方法。函數OCIAttrGet()函數能夠返回很多句柄的屬性,這里我們就要用到這個函數。先看一下它的原型和參數。
sword OCIAttrGet ( const void *trgthndlp,
ub4 trghndltyp,
void *attributep,
ub4 *sizep,
ub4 attrtype,
OCIError *errhp );
trgthndlp是一個輸入參數,指向一個需要獲取屬性的句柄。
trghndltyp是一個輸入參數,指定句柄的類型,我們這里用到的是OCI語句句柄OCI_HTYPE_STMT。
attributep是一個輸出參數,返回屬性值。
sizep是一個輸出參數,返回屬性值的大小。
attrtype是一個輸入參數,指定屬性的類型,我們這里用到OCI_ATTR_ROWS_FETCHED。
errhp是一個輸入/輸出參數,錯誤句柄,用于返回錯誤碼和錯誤信息文本。
獲取每次從結果集中得到的數據實際條數的用法如下。
ub4 rows;
ub4 asz = sizeof(ub4);
OCIAttrGet((const void *)stmtp, (ub4)OCI_HTYPE_STMT,
(void *)&rows, (ub4 *)&asz, (ub4)OCI_ATTR_ROWS_FETCHED, errhp);
在OCIStmtFetch()函數之后調用上面的函數,rows中就是這次從結果集中返回的數據條數。
我們還是看一個完整的例子,從test_tab中查詢所有數據,注意看程序是怎樣查詢完畢結束循環的,與單條查詢還是有區別的。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; /* 數組查詢數據 */ int query_array(void){ Int i; Sword rc; Int slen; ub4 rrows; ub4 asz; 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 id_str[64]; char name[10][32]; char addr[10][256]; OCIDefine *defp; 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); } /* 生成查詢語句文本 */ strcpy(sqltxt, "SELECT ID, NAME, ADDR FROM test_tab"); 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, OCIDefineByPos((OCIStmt *)smthp, (OCIDefine **)&defp, 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)OCI_DEFAULT) /* mode */ ) < 0) return (-1); if (check_oci_error(errhp, OCIDefineArrayOfStruct(defp, errhp, 4, 2, 2, 2)) < 0) return (-1); /* 定義第二個字段NAME的輸出變量 */ if (check_oci_error(errhp, OCIDefineByPos((OCIStmt *)smthp, (OCIDefine **)&defp, 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)OCI_DEFAULT) /* mode */ ) < 0) return (-1); if (check_oci_error(errhp, OCIDefineArrayOfStruct(defp, errhp, 32, 2, 2, 2)) < 0) return (-1); /*定義第三個字段ADDR的輸出變量 */ if (check_oci_error(errhp, OCIDefineByPos((OCIStmt *)smthp, (OCIDefine **)&defp, 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)OCI_DEFAULT) /* mode */ ) < 0) return (-1); if (check_oci_error(errhp, OCIDefineArrayOfStruct(defp, errhp, 256, 2, 2, 2)) < 0) return (-1); /* 執行OCI語句,注意在查詢語句執行時,iters要設置為0 */ if (check_oci_error(errhp, OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 0, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT) /* mode */ ) < 0) return (-1); while (1) { /* 注意這里nrows要設置為10,是數組元素的最大個數 */ if ((rc = check_oci_error(errhp, OCIStmtFetch(smthp, errhp, 10, OCI_FETCH_NEXT, OCI_DEFAULT))) < 0) return (-1); if (check_oci_error(errhp, OCIAttrGet((const void *)smthp, (ub4)OCI_HTYPE_STMT, (void *)&rrows, (ub4 *)&asz, (ub4)OCI_ATTR_ROWS_FETCHED, errhp) ) < 0) return (-1); for (i=0; i<rrows; i++) { if (ind_id[i] == -1) sprintf(id_str, "NULL"); else sprintf(id_str, "%d", id[i]); if (ind_name[i] == -1) sprintf(name[i], "NULL"); if (ind_addr[i] == -1) sprintf(addr[i], "NULL"); fprintf(stdout, "ID=%s, NAME=%s, ADDR=%s\n", id_str, name[i], addr[i]); } /* 結果集中沒有數據了,退出循環,一定要處理完前面的數據再判斷 */ if (rc == OCI_NO_DATA) break; } return (0); }

浙公網安備 33010602011771號