访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。
查询数据是OCI程序中的一个常用的操作,它不会对数据库的数据产生改变,操作的步骤也与更新操作的步骤有区别,用到了不一样的函数。下面先看一下查询操作的步骤。
1. 分配OCI语句句柄,用到函数OCIHandleAlloc()。
2. 准备SQL语句,用到函数OCIStmtPrepare()。
3. 定义每个查询字段输出变量,用到函数OCIDefineByPos()。
4. 执行OCI语句,用到函数OCIStmtExecute()。
5. 取回查询结果,用到函数OCIStmtFetch()。
下面看一下用到的新函数原型和参数。
第一个函数,定义输出变量函数。
sword OCIDefineByPos ( OCIStmt *stmtp,
OCIDefine **defnpp,
OCIError *errhp,
ub4 position,
void *valuep,
sb4 value_sz,
ub2 dty,
void *indp,
ub2 *rlenp,
ub2 *rcodep,
ub4 mode );
stmtp是一个输入/输出参数,是分配的查询语句句柄。
defnpp是一个输入/输出参数,是跟查询列表中的字段对应的定义句柄,存放本字段相关的信息,如果不需要,可以赋值为NULL。
errhp是一个输入/输出参数,是错误句柄,用于获取错误码和错误信息文本。
position是一个输入参数,是查询列表中字段的位置,从1开始计算。
valuep是一个输入/输出参数,指向输出变量的地址或一个输出数组的地址。
value_sz是一个输入参数,指定valuep存储缓冲区的大小,以字节计算。
dty是一个输入参数,是查询列表中字段的数据类型,与绑定函数中的定义一致。
indp是一个输入参数,是指示变量指针,如果查询的字段返回值为NULL,指示变量返回值为-1。
rlenp是一个输入/输出参数,是返回结果的字段值的实际大小。
rcodep是一个输出参数,返回字段级别的错误码。
mode是一个输入参数,指示定义函数的模式,一般取值为OCI_DEFAULT。
第二个函数,取回查询结果函数。
sword OCIStmtFetch ( OCIStmt *stmtp,
OCIError *errhp,
ub4 nrows,
ub2 orientation,
ub4 mode );
stmtp是一个输入参数,查询语句的OCI句柄。
errhp是一个输入参数,错误句柄,用于返回错误码和错误信息文本。
nrows是一个输入参数,希望取回的数据条数。
orientation是一个输入参数,获取数据的方向,取值为OCI_FETCH_NEXT,获取下一条数据。
mode是一个输入参数,取值为OCI_DEFAULT。
我们还是通过一个实际的例子来看看这些函数的用法,还是使用前面创建的表test_tab,从里面查询数据的SQL语句为SELECT ID, NAME, ADDR FROM test_tab。其中ID, NAME, ADDR就是查询列表字段。下面看看用OCI程序怎样操作。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL;/* 查询数据 */
int select_data(void){sword rc;int slen;sb2 ind_id;sb2 ind_name;sb2 ind_addr;ub2 alen_id;ub2 alen_name;ub2 alen_addr;ub2 rcode_id;ub2 rcode_name;ub2 rcode_addr;int32_t id;char id_str[64];char name[32];char addr[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);/* 定义第二个字段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);/*定义第三个字段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);/* 执行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) {if ((rc = check_oci_error(errhp,OCIStmtFetch(smthp, errhp, 1,OCI_FETCH_NEXT, OCI_DEFAULT))) < 0)return (-1);/* 返回的结果集中没有数据了,退出循环 */if (rc == OCI_NO_DATA)break;if (ind_id == -1)sprintf(id_str, "NULL");elsesprintf(id_str, "%d", id);if (ind_name == -1)sprintf(name, "NULL");if (ind_addr == -1)sprintf(addr, "NULL");fprintf(stdout, "ID=%s, NAME=%s, ADDR=%s\n", id_str, name, addr);}return (0); }
如果查询语句中有WHERE条件,那么条件字段会用占位符表示,通过绑定函数来关联占位符和条件变量值。比如查询ID=1的数据,那么OCI程序中的语句文本为SELECT ID, NAME, ADDR FROM test_tab WHERE ID=:1。占位符:1通过OCIBindByPos()函数来绑定数值。