当前位置: 首页 > article >正文

unixODBC编程(三)查询数据库表中的数据

连接数据库成功后,就可以对数据库进行操作了,我们先看一下怎样从数据库表中查询数据。查询数据在ODBC中也有几个步骤。

1. 分配一个语句句柄,使用SQLAllocHandle()函数,句柄类型为SQL_HANDLE_STMT。

2. 准备语句,使用SQLPrepare()函数。

3. 执行语句,使用SQLExecute()函数。

4. 绑定输出的变量,使用SQLBindCol()函数。

5. 循环取回结果集数据,使用SQLFetch()函数。

下面看看这几个函数的原型和参数。

准备语句函数。

SQLRETURN SQLPrepare(
     SQLHSTMT       StatementHandle,
     SQLCHAR *       StatementText,
     SQLINTEGER    TextLength);

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

StatementText是一个输入参数,SQL文本字符串。

TextLength是一个输入参数,SQL文本字符串 StatementText 的长度。

执行语句函数。

SQLRETURN SQLExecute(
     SQLHSTMT     StatementHandle);

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

绑定输出变量函数。

SQLRETURN SQLBindCol(
      SQLHSTMT           StatementHandle,
      SQLUSMALLINT   ColumnNumber,
      SQLSMALLINT      TargetType,
      SQLPOINTER        TargetValuePtr,
      SQLLEN                 BufferLength,
      SQLLEN *               StrLen_or_IndPtr);

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

ColumnNumber是一个输入参数,要绑定的结果集列的序号。列从 0 开始递增编号,其中列 0 是书签列。如果没有使用书签列,则列号从 1 开始。

TargetType是一个输入参数,是TargetValuePtr 缓冲区的 C 数据类型。

TargetValuePtr是一个输入/输出参数,指向要绑定到列的数据缓冲区的指针。

BufferLength是一个输入参数,TargetValuePtr 缓冲区的长度(以字节为单位)。

StrLen_or_IndPtr是一个输入/输出参数,指向要绑定到列的长度/指示器缓冲区的指针。

取回结果集中数据的函数。

SQLRETURN SQLFetch(
     SQLHSTMT     StatementHandle);

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

现在来看一个例子,连接到数据库后,从user_table中查询表名,表空间名和表的状态。SQL语句为select table_name, tablespace_name, status from user_tables。

#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      rlen1;
    SQLLEN      rlen2;
    SQLLEN      rlen3;
    char        dsn_str[32];
    char        usrname[32];
    char        passwd[32];
    char        table_name[256];
    char        ts_name[32];
    char        status[16];


    /* 从命令行参数中输入数据源名称,数据库用户名和密码 */
    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);
    }

    /* 设置ODBC版本 */
    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;
    }

    /* 准备SQL语句文本 */
    rc = SQLPrepare(stmth,
        (SQLCHAR *)"select table_name, tablespace_name, status from user_tables",
        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;
    }

    /* 绑定第一列的输出变量,类型是C语言的char类型,rlen1是返回的数据长度 */
    rc = SQLBindCol(stmth, 1, SQL_C_CHAR, (SQLCHAR *)table_name, 256, &rlen1);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 1 error.\n");
        goto free_exit;
    }

    /* 绑定第二列输出变量 */
    rc = SQLBindCol(stmth, 2, SQL_C_CHAR, (SQLCHAR *)ts_name, 32, &rlen2);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 2 error.\n");
        goto free_exit;
    }

    /* 绑定第三列输出变量 */
    rc = SQLBindCol(stmth, 3, SQL_C_CHAR, (SQLCHAR *)status, 16, &rlen3);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 3 error.\n");
        goto free_exit;
    }

    while (1) {
        /* 返回结果集数据 */
        rc = SQLFetch(stmth);

        if (rc == SQL_NO_DATA) {
            /* 结果集中没有数据了,退出循环 */
            break;
        } else if (rc == SQL_ERROR) {
            /* 出错,返回 */
            fprintf(stderr, "Fetch data error.\n");
            goto free_exit;
        }

        /* 打印返回的变量值 */
        fprintf(stdout, "table_name=%s, tablespace_name=%s, status=%s\n",
            table_name, ts_name, status);
    }

    /* 释放语句句柄 */
    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);
}

编译程序,需要包含unixODBC的include路径和连接库的路径,比如源文件叫odbc_test.c,编译命令如下。

cc -I$HOME/unixODBC/include -L$HOME/unixODBC/lib -lodbc odbc_test.c


http://www.kler.cn/a/325492.html

相关文章:

  • AWTK-WIDGET-WEB-VIEW 实现笔记 (1) - 难点
  • uniapp自动注册机制:easycom
  • 计算机网络:运输层 —— TCP的流量控制
  • 大数据-226 离线数仓 - Flume 优化配置 自定义拦截器 拦截原理 了 拦截器实现 Java
  • 【Node.js】使用 Node.js 需要了解多少 JavaScript?
  • Python数据分析:分组转换transform方法
  • LangChain:构建复杂 NLP 应用的框架
  • ENV | docker 安装使用(简单实操版)
  • Llama 3.2来了,多模态且开源!AR眼镜黄仁勋首批体验,Quest 3S头显价格低到离谱
  • C语言介绍
  • Object Pascal 过程与函数
  • Ubuntu网卡配置
  • rabbitMQ 简单使用
  • 23中设计模式,以及三种常见的设计模式demo
  • 使用::selection改变文字被选中后的颜色
  • 深圳mes制造系统的主要功能
  • WIFI密码默认显示
  • OpenAI员工流失的背后:地盘争夺、倦怠、薪酬要求
  • 大模型+AIGC技术实操:GPT 大模型部署使用 AIGC实战落地方案
  • LeetCode讲解篇之3. 无重复字符的最长子串
  • springboot异常(三):异常处理原理
  • 超详细的华为ICT大赛报名流程
  • golang学习笔记32——哪些是用golang实现的热门框架和工具
  • Android Webview和ScrollView冲突和WebView使用总结
  • 数仓建模:DataX同步Mysql数据到Hive如何批量生成建表语句?| 基于SQL实现
  • cuda程序编译流程