unixODBC编程(八)使用滚动游标

Cursor是光标的意思,指的是在计算机屏幕上闪烁的一个亮块或一条竖线,如果在一个文字编辑的屏幕上就更好理解了,光标会随着键盘的上下左右键相应的移动。这个词在数据库查询的结果集中使用时就翻译成了游标,与光标的区别是它只能上下移动,代表在不同的数据行间选择。

在一条查询语句被执行后,就生成了一个结果集,这时游标处在第一行数据之前,所以取回(fetch)下一条数据(SQL_FETCH_NEXT)就是取回第一条数据。调用一次fetch函数,游标就停在fetch回的最后一条数据上,如果只取回一条,那么游标就在这条数据上,如果取回多条(使用数组取回),那么游标就停在最后一条数据上。

前面我们用到的SQLFetch()函数只能取回下一条数据,使用的是一种只能向前滚动的游标,如果要取回当前数据之前的某条数据就会比较麻烦,只能重新执行查询语句,然后再fetch到想要的那条数据,即浪费时间,有操作复杂。为解决这样的问题,ODBC提供了滚动游标(scrollable cursor),这种游标可以从任意位置取回结果集中的数据行。要使用滚动游标,需要设置语句属性SQL_ATTR_CURSOR_SCROLLABLE,属性值为SQL_SCROLLABLE,设置这个属性的位置有些特别,要在分配语句句柄后设置,在SQLPrepare()或SQLExecDirect()函数调用之前,否则会出错。

在执行语句后生成了结果集,这时就可以使用滚动游标了,取回数据的函数要使用SQLFetchScroll(),而不是SQLFetch()。我们看一下SQLFetchScroll()的函数原型和参数。

SQLRETURN SQLFetchScroll(
      SQLHSTMT        StatementHandle,
      SQLSMALLINT   FetchOrientation,
      SQLLEN              FetchOffset);

StatementHandle是一个输入参数,查询语句的句柄。

FetchOrientation是一个输入参数,取回数据的方向值。取值如下:

SQL_FETCH_NEXT(取下一条)
SQL_FETCH_PRIOR(取当前行的前一条)
SQL_FETCH_FIRST(取第一行)
SQL_FETCH_LAST(取最后一行)
SQL_FETCH_ABSOLUTE(按绝对行号取数据)
SQL_FETCH_RELATIVE(按相对行号取数据)
SQL_FETCH_BOOKMARK(按书签取数据)

FetchOffset是一个输入参数,取数据的行号偏移量。对于绝对行号取数据,偏移量就是某个行号,表示取结果集中的第几行。对于相对行号取数据,偏移量就是相对于当前行偏移几行,如果是正数,就是当前行加偏移行的行号,如果是负数,就是当前行减去偏移行的行号。

我们看一个实际的例子,怎样设置滚动游标属性,怎样使用SQLFetchScroll()函数。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sql.h"
#include "sqlext.h"
#include "sqltypes.h"

SQLHANDLE       envh;           /* env handle */
SQLHANDLE       dbch;           /* connect handle */
SQLHANDLE       stmth;          /* statement handle */

int main(int argc, char *argv[])
{
    int                 i;
    int                 conn = 0;
    SQLRETURN           rc;
    SQLLEN              len_ind1;
    SQLLEN              len_ind2;
    SQLLEN              len_ind3;
    SQLLEN              len_ind4;
    SQLLEN              len_ind5;
    SQLINTEGER          id;
    char                dsn_str[32];
    char                usrname[32];
    char                passwd[32];
    char                sqltxt[128];
    char                f1[32];
    char                f2[32];
    char                f3[32];
    char                f4[32];


    if (argc < 3) {
        fprintf(stderr, "usage: %s dsn username password\n", argv[0]);
        return (-1);
    }

    strncpy(dsn_str, argv[1], 32);
    dsn_str[31] = '\0';
    strncpy(usrname, argv[2], 32);
    usrname[31] = '\0';
    strncpy(passwd, argv[3], 32);
    passwd[31] = '\0';

    rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &envh);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Allocate environment handle error.\n");
        return (-1);
    }

    rc = SQLSetEnvAttr(envh, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Set ODBC version error.\n");
        goto free_exit;
    }

    rc = SQLAllocHandle(SQL_HANDLE_DBC, envh, &dbch);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Allocate DB connection handle error.\n");
        goto free_exit;
    }

    rc = SQLSetConnectAttr(dbch, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)10, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Set connection timeout value error.\n");
        goto free_exit;
    }

    rc = SQLConnect(dbch, (SQLCHAR *)dsn_str, SQL_NTS, (SQLCHAR *)usrname, SQL_NTS,
        (SQLCHAR *)passwd, SQL_NTS);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Connect to DB error.\n");
        goto free_exit;
    }

    conn = 1;
    fprintf(stdout, "connect DB ok ......\n");

    rc = SQLAllocHandle(SQL_HANDLE_STMT, dbch, &stmth);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Allocate statment handle error.\n");
        goto free_exit;
    }

    /* 设置结果集使用滚动游标 */
    rc = SQLSetStmtAttr(stmth, SQL_ATTR_CURSOR_SCROLLABLE,
        (SQLPOINTER)SQL_SCROLLABLE, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Set statment attribute error.\n");
        goto free_exit;
    }

    /* 准备语句 */
    sprintf(sqltxt, "select id, f1, f2, f3, f4 from my_tredo1");
    rc = SQLPrepare(stmth, (SQLCHAR *)sqltxt, SQL_NTS);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Prepare statment error.\n");
        goto free_exit;
    }

    rc = SQLBindCol(stmth, 1, SQL_C_ULONG, (SQLPOINTER)&id, 0, &len_ind1);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 1 error.\n");
        goto free_exit;
    }

    rc = SQLBindCol(stmth, 2, SQL_C_CHAR, (SQLPOINTER)f1, 32, &len_ind2);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 2 error.\n");
        goto free_exit;
    }

    rc = SQLBindCol(stmth, 3, SQL_C_CHAR, (SQLPOINTER)f2, 32, &len_ind3);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 3 error.\n");
        goto free_exit;
    }

    rc = SQLBindCol(stmth, 4, SQL_C_CHAR, (SQLPOINTER)f3, 32, &len_ind4);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 4 error.\n");
        goto free_exit;
    }

    rc = SQLBindCol(stmth, 5, SQL_C_CHAR, (SQLPOINTER)f4, 32, &len_ind5);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 4 error.\n");
        goto free_exit;
    }

    rc = SQLExecute(stmth);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Execute statment error.\n");
        goto free_exit;
    }

    /* 先使用SQL_FETCH_NEXT参数,把结果集中的数据行都打印出来 */
    for (i=1; ;i++) {
        rc = SQLFetchScroll(stmth, SQL_FETCH_NEXT, 0);

        if (rc == SQL_NO_DATA) {
            fprintf(stderr, "no data in result set, break.\n");
            break;
        } else if (rc == SQL_ERROR) {
            fprintf(stderr, "Fetch data error.\n");
            goto free_exit;
        }

        fprintf(stdout, "row[%02d] id=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
            i, id, f1, f2, f3, f4);
    }

    /* 取回第一条数据,打印显示 */
    rc = SQLFetchScroll(stmth, SQL_FETCH_FIRST, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Fetch the first row error.\n");
        goto free_exit;
    }

    fprintf(stderr, "The first row:\nid=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
        id, f1, f2, f3, f4);

    /* 取回最后一条数据,打印显示 */
    rc = SQLFetchScroll(stmth, SQL_FETCH_LAST, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Fetch the last row error.\n");
        goto free_exit;
    }

    fprintf(stderr, "The last row:\nid=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
        id, f1, f2, f3, f4);

    /* 取回倒数第二行数据,打印显示 */
    rc = SQLFetchScroll(stmth, SQL_FETCH_PRIOR, 0);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Fetch the second to last row error.\n");
        goto free_exit;
    }

    fprintf(stderr, "The second to last row:\nid=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
        id, f1, f2, f3, f4);

    /* 使用相对行号,取回倒数第二条的前一条,就是倒数第三行的数据 */
    rc = SQLFetchScroll(stmth, SQL_FETCH_RELATIVE, -1);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Fetch the third to last row error.\n");
        goto free_exit;
    }

    fprintf(stderr, "The third to last row:\nid=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
        id, f1, f2, f3, f4);

    /* 使用绝对行号,取回第五行的数据 */
    rc = SQLFetchScroll(stmth, SQL_FETCH_ABSOLUTE, 5);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Fetch the fifth row error.\n");
        goto free_exit;
    }

    fprintf(stderr, "The fifth row:\nid=%d, f1=%s, f2=%s, f3=%s, f4=%s\n",
        id, f1, f2, f3, f4);

    /* 关闭游标 */
    SQLCloseCursor(stmth);

    SQLFreeHandle(SQL_HANDLE_STMT, stmth);

    SQLDisconnect(dbch);

    SQLFreeHandle(SQL_HANDLE_DBC, dbch);

    SQLFreeHandle(SQL_HANDLE_ENV, envh);

    return (0);

free_exit:
    if (stmth != NULL) {
        SQLFreeHandle(SQL_HANDLE_STMT, stmth);
    }

    if (conn) {
        SQLDisconnect(dbch);
    }

    if (dbch != NULL) {
        SQLFreeHandle(SQL_HANDLE_DBC, dbch);
    }

    if (envh != NULL) {
        SQLFreeHandle(SQL_HANDLE_ENV, envh);
    }

    return (-1);
}

访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值