unixODBC编程(八)使用滚动游标
访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。
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工具的源代码,学习高技术含量的内容。

浙公网安备 33010602011771号