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

unixODBC编程(十)分片插入长数据

遇到有LONG数据类型的表,要插入一条数据量很大的行,一次插入的缓冲区会不够大,这时需要一部分一部分的插入LONG数据,这就用到了在执行语句时动态提供数据的机制。在ODBC中要动态提供数据需要几个步骤。

1. 在绑定输入参数时,要在SQLBindParameter()函数中指定数据长度时,使用SQL_LEN_DATA_AT_EXEC()宏得到数据长度,告诉应用程序数据在执行语句时才提供,使用的数据类型要用SQL_LONGVARCHAR或SQL_LONGBINARY。同时数据指针要提供一个数值,标记这个字段,为了区分多个动态插入的字段,这个数值在后面调用SQLParamData()函数时会返回,这样应用程序就知道现在是哪个字段需要提供数据。

2. 执行SQLExecute()或SQLExecDirect()函数,因为语句中有动态字段,所以函数会返回SQL_NEED_DATA的返回值。

3. 调用SQLParamData()函数,返回标识字段的数值,这时就知道是为哪个字段插入数据。函数返回SQL_NEED_DATA,这时需要提供数据。

4. 循环调用SQLPutData()函数,为字段提供动态数据,直到插入的数据完毕。

5. 再次调用SQLParamData()函数,看看是否还有下一个动态插入的字段需要操作,函数返回SQL_NEED_DATA,说明需要为新字段提供数据,重复步骤4的操作。如果返回SQL_SUCCESS,说明没有要提供数据的字段了,把上一个动态插入数据的系列操作结束。

举一个例子,在test_long1表中插入LONG数据,字段叫summary,插入10000个字符。SQLBindParameter()函数的StrLen_or_IndPtr参数设置为SQL_LEN_DATA_AT_EXEC(10000),ParameterType设置为SQL_LONGVARCHAR,ParameterValuePtr设置为参数的编号,比如编号为3,那么函数设置如下。

len_ind3 = SQL_LEN_DATA_AT_EXEC(10000);
SQLBindParameter(stmth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 10000, 0, (void *)3, 0, &len_ind3);
下面我们看一个实际的例子,在test_long1表中插入一条数据,绑定三个参数,后面两个参数都使用动态提供数据,主要看看SQLParamData()函数和SQLPutData()函数的用法,以及如何动态提供数据。代码如下。

#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      len_ind1;
    SQLLEN      len_ind2;
    SQLLEN      len_ind3;
    SQLLEN      total_amt;
    SQLLEN      once_amt;
    SQLINTEGER  id;
    SQLPOINTER  param_id;
    char        dsn_str[32];
    char        usrname[32];
    char        passwd[32];
    char        sqltxt[512];
    char        data[4096];


    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;
    }

    /* 插入一条数据,输入三个参数,note和summary动态提供数据 */
    sprintf(sqltxt, "insert into test_long1 (id, name, addr, note, summary) values (?, 'AAAAAAAA', 'BBBBBBBBBB', ?, ?)");
    rc = SQLPrepare(stmth, (SQLCHAR *)sqltxt, SQL_NTS);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Prepare statment error.\n");
        goto free_exit;
    }

    /* ID字段的插入值为10 */
    id = 10;

    /* ID正常插入,在绑定时提供数值
     * NOTE在执行时动态提供数据,长度为40,数据为40个'C'字符,一次提供完毕
     * SUMMARY在执行是动态提供数据,长度为10000,数据为10000个'D'字符,分多次提供
     * NOTE和SUMMARY字段使用SQL_LEN_DATA_AT_EXEC()宏计算长度
     */
    len_ind1 = 0;
    len_ind2 = SQL_LEN_DATA_AT_EXEC(40);
    len_ind3 = SQL_LEN_DATA_AT_EXEC(10000);

    /* 绑定变量id */
    rc = SQLBindParameter(stmth, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER,
        0, 0, &id, 0, &len_ind1);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 1 error.\n");
        goto free_exit;
    }

    /* 参数类型为SQL_LONGVARCHAR,数据指针指向参数编号2 */
    rc = SQLBindParameter(stmth, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR,
        2000, 0, (void *)2, 0, &len_ind2);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 2 error.\n");
        goto free_exit;
    }

    /* 参数类型为SQL_LONGVARCHAR,数据指针指向参数编号3 */
    rc = SQLBindParameter(stmth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR,
        10000, 0, (void *)3, 0, &len_ind3);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "Bind column 3 error.\n");
        goto free_exit;
    }

    /* 执行插入语句,这时函数返回SQL_NEED_DATA */
    rc = SQLExecute(stmth);
    if ((rc != SQL_SUCCESS) && (rc != SQL_NEED_DATA)) {
        fprintf(stderr, "Execute statment error.\n");
        goto free_exit;
    }

    /* 循环检查动态提供数据的字段 */
    while (1) {
        /* 调用SQLParamData()函数,parma_id返回绑定时指定的参数编号 */
        rc = SQLParamData(stmth, &param_id);
        if ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO))
            /* 返回SQL_SUCCESS说明所有动态提供数据的字段都操作完成了,退出循环 */
            break;

        if (rc != SQL_NEED_DATA) {
            /* 这里如果返回值不为SQL_NEED_DATA说明函数调用出错了 */
            fprintf(stderr, "Call SQLParamData() error.\n");
            goto free_exit;
        }

        if (param_id == (SQLPOINTER)2) {
            /* param_id等于2,说明要为第二个参数提供数据,提供40个'C'字符 */
            memset(data, 'C', 40);
            data[40] = '\0';
            len_ind2 = 40;
            /* 调用SQLPutData()函数,为参数2提供数据 */
            rc = SQLPutData(stmth, (SQLPOINTER)data, len_ind2);
            if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
                fprintf(stderr, "Call SQLPutData() error.\n");
                goto free_exit;
            }
        } else if (param_id == (SQLPOINTER)3) {
            /* param_id等于3,说明要为第三个参数提供数据,提供10000个'D'字符
             * 每次提供4000字符,分三次提供完毕
             */
            once_amt = 4000;
            total_amt = 10000;
            memset(data, 'D', 4000);
            data[4000] = '\0';
            while (total_amt > once_amt) {
                /* 每次提供4000字符 */
                rc = SQLPutData(stmth, (SQLPOINTER)data, once_amt);
                if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
                    fprintf(stderr, "Call SQLPutData() error.\n");
                    goto free_exit;
                }

                total_amt -= once_amt;
            }

            if (total_amt > 0) {
                /* 提供最后的2000字符 */
                rc = SQLPutData(stmth, (SQLPOINTER)data, total_amt);
                if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) {
                    fprintf(stderr, "Call SQLPutData() error.\n");
                    goto free_exit;
                }
            }
        } else {
            fprintf(stderr, "Invalid parameter number.\n");
            goto free_exit;
        }
    }

    /* 提交改变的数据 */
    rc = SQLEndTran(SQL_HANDLE_DBC, dbch, SQL_COMMIT);
    if (rc != SQL_SUCCESS) {
        fprintf(stderr, "End Transaction error.\n");
        goto free_exit;
    }

    fprintf(stdout, "Insert data successed ......\n");

    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.kler.cn/news/330887.html

相关文章:

  • Unity实战案例全解析:RTS游戏的框选和阵型功能(3)生成范围检测框 +重置框选操作
  • MySQL进阶篇 - 存储引擎
  • 硬件-开关电源-结构组成及元件作用
  • visual studio2022添加新项中没有html和css
  • 深入理解人工智能:从机器学习到深度学习
  • 过渡到内存安全语言:挑战和注意事项
  • 机器学习西瓜书笔记(十三) 第十三章半监督学习+代码
  • 软件工程-软件测试
  • [Notepad++] 文本编辑器的下载及详细安装使用过程(附有下载文件)
  • python-斐波那契词序列/最大回文乘积/求最大最小k个元素
  • EasyCVR视频汇聚平台:解锁视频监控核心功能,打造高效安全监管体系
  • C语言 | Leetcode C语言题解之第450题删除二叉搜索树中的节点
  • java将mysql表结构写入到word表格中
  • 小程序-全局数据共享
  • 【Linux系统编程】权限
  • 广联达 Linkworks办公OA Service.asmx接口存在信息泄露漏洞
  • LeetCode 704. 二分查找
  • 2024年09月CCF-GESP编程能力等级认证C++编程一级真题解析
  • @antv/x6 嵌入结点到父节点中时,进行检测,查看当前节点是否是父结点,如果是父结点,不可以嵌入到父结点中,实现方法一。
  • 【AIGC】内容创作——AI文字、图像、音频和视频的创作流程