当一个表中有长数据类型的字段,比如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工具的源代码,学习高技术含量的内容。