当一个表中有长数据类型的字段,比如LONG数据类型,LONG RAW数据类型,字段存储的数据可能比较大,不可能在程序中定义这样大的缓冲区,这时就需要一部分一部分的读取数据,比如字段中存放了一个大的图片数据,现在取出来存储成一个图片文件,那么就可以定义一个合适的缓冲区,每次读取一部分数据,边读边写入文件。这时就需要用到一个函数SQLGetData(),先看一下函数原型和参数。
SQLRETURN SQLGetData(
SQLHSTMT StatementHandle,
SQLUSMALLINT Col_or_Param_Num,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
StatementHandle是一个输入参数,查询语句的句柄。
Col_or_Param_Num是一个输入参数,结果集中列的编号,从1开始编号。
TargetType是一个输入参数,是列的数据类型对应的C语言类型。比如SQL_C_CHAR,SQL_C_SLONG,SQL_C_SSHORT,SQL_C_FLOAT等。
TargetValuePtr是一个输出参数,指向存储数据的缓冲区,不能为NULL。
BufferLength是一个输入参数,上面缓冲区的长度。
StrLen_or_IndPtr是一个输出参数,指示返回的数据长度,或空数据(SQL_NULL_DATA)。
这个函数要从结果集中取数据,所以需要游标在要取数的那行数据上,所以要在SQLFetch()或SQLFetchScroll()函数之后调用。
看一个实际的例子,有一个表叫做test_long1,有两个字段id和summary,id是整数类型,summary是LONG类型。从这个表中查询一条数据,id通过SQLBindCol()函数获取,summary通过SQLGetData()函数获取,代码如下。
#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 conn = 0;SQLRETURN rc;SQLLEN rlen_ind1;SQLLEN rlen_ind2;SQLINTEGER id;char dsn_str[32];char usrname[32];char passwd[32];char sqltxt[128];char buf[256];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;}sprintf(sqltxt, "select id, summary from test_long1 where id=11");rc = SQLPrepare(stmth, (SQLCHAR *)sqltxt, SQL_NTS);if (rc != SQL_SUCCESS) {fprintf(stderr, "Prepare statment error.\n");goto free_exit;}/* 执行语句,产生结果集 */rc = SQLExecute(stmth);if (rc != SQL_SUCCESS) {fprintf(stderr, "Execute statment error.\n");goto free_exit;}/* 绑定ID字段的输出变量 */rc = SQLBindCol(stmth, 1, SQL_C_ULONG, (SQLPOINTER)&id, 0, &rlen_ind1);if (rc != SQL_SUCCESS) {fprintf(stderr, "Bind column 1 error.\n");goto free_exit;}/* 调用SQLFetch()使得游标定位在第一条数据上,也就是我们要取数的数据行上 */rc = SQLFetch(stmth);if (rc == SQL_NO_DATA) {fprintf(stderr, "no data in result set.\n");} else if (rc == SQL_ERROR) {fprintf(stderr, "Fetch data error.\n");goto free_exit;} else if (rc == SQL_SUCCESS) {/* fetch成功,取得ID的值,下面通过SQLGetData()函数,一部分一部分的读取summary的值 */fprintf(stdout, "id=%d\nsummary:\n", id);while (1) {rc = SQLGetData(stmth, 2, SQL_C_CHAR, buf, 256, &rlen_ind2);if (rc == SQL_NO_DATA)break;if (rc == SQL_ERROR) {fprintf(stderr, "Get data from column error.\n");goto free_exit;}if (rc == SQL_SUCCESS) {/* 调用成功,打印这部分的数据 */fprintf(stdout, "%s\n", buf);}}}/* 关闭游标,游标可以隐式打开,但一定要显式关闭 */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工具的源代码,学习高技术含量的内容。