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