在前面的章节介绍数据查询时,也是一条条的从结果集中返回数据,大数据量查询仍然是个瓶颈,好在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);
}