OCI编程高级篇(二) 数组查询

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


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值