unixODBC编程(九)分片查询长数据

server/2024/10/16 2:26:05/

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


http://www.ppmy.cn/server/126852.html

相关文章

Rust Web开发常用库

本集合中所有库都是在开源项目中广泛使用且在2024年积极维护的库&#xff0c;排名靠前的库是当前使用比较广泛的&#xff0c;不全面但够用 Rust异步运行时 tokio&#xff1a;异步运行时 async_std&#xff1a;与标准库兼容性较强的运行时 monoio&#xff1a;字节开源 smol…

SpringCloud入门(十)统一网关Gateway

一、网关的作用 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关&#xff0c;它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 …

基于RBAC的通用权限管理系统的详细分析与实现(实现篇-Spring Security安全管理框架)

安全可以说是公司的红线了&#xff0c;一般项目都会有严格的认证和授权操作&#xff0c;在Java开发领域常见的安全框架有Shiro和Spring Security。 Shiro是一个轻量级的安全管理框架&#xff0c;提供了认证、授权、会话管理、密码管理、缓存管理等功能。 Spring Security是一…

AQS原理(AbstractQueuedSynchronizer)

本篇为 [并发与多线程系列] 的第四篇&#xff0c;对应Java知识体系脑图中的 并发与多线程 模块。 这一系列将对Java中并发与多线程的内容来展开。 AQS原理&#xff08;AbstractQueuedSynchronizer&#xff09; AQS原理&#xff08;AbstractQueuedSynchronizer&#xff09;AQS整…

Python知识点:如何使用Raspberry Pi与Python进行边缘计算

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 如何使用Raspberry Pi与Python进行边缘计算 Raspberry Pi是一款广受欢迎的小型单…

移动端的每日任务,golang后端数据库应该怎么设计

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…

491. 递增子序列

文章目录 491. 递增子序列思路回溯三部曲总结 491. 递增子序列 491. 递增子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如…

std::map

std::map是C标准库中的一个关联容器&#xff0c;它基于红黑树实现&#xff0c;用于存储键值对。与标准数组或向量不同&#xff0c;std::map允许你根据键来快速检索、插入和删除元素。正如std::vector包含在< vector >头文件中&#xff0c;std::map包含在< map >头文…