访问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");elsesprintf(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);
}