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号