OCI编程高级篇(四) 分片插入

当插入表中的一个字段,数据量比较大时怎么处理呢?我们在前面介绍OCIBindByPos()函数时看到,指示数据实际长度的参数alenp是一个ub2类型的整数,也就是说,绑定的数据量最大只有16K字节。当然大部分的字段长度都达不到这么大,但有两个特殊类型LONG和LONG RAW字段的长度最大可以存储2G的数据,如果向这样的字段中插入超过16K的数据,还有没有办法呢?OCI提供了一种叫做分片操作的方法,可以应对这种状况。分片操作顾名思义就是把大的数据分割成小的数据片,一片接一片的插入字段中。

要使用OCI的分片操作,首先在字段变量绑定时要用到OCI_DATA_AT_EXEC模式,就是在运行时提供数据,这里的绑定操作不关联具体的变量。操作步骤如下。

1. 分配OCI语句句柄。

2. 准备SQL语句文本,分析语法。

3. 绑定占位符变量,OCIBindByPos()使用OCI_DATA_AT_EXEC模式。

4. 执行语句,OCIStmtExecute(),这次不会插入任何数据,返回码OCI_NEED_DATA。

5. 提供数据,调用OCIStmtSetPieceInfo()函数,设置数据缓冲区地址和数据大小,指示分片的类型,第一片为OCI_FIRST_PIECE,下一片为OCI_NEXT_PIECE,最后一片为OCI_LAST_PIECE。

6. 执行语句,调用OCIStmtExecute()函数,这次会真正的插入数据片,如果上一步分片数据为OCI_LAST_PIECE,那么执行后返回码为OCI_SUCCESS,程序插入数据完毕。否则返回码为OCI_NEED_DATA,需要返回第五步,设置下一片数据地址和长度,继续这一步的执行操作,直到最后一片数据,退出循环。

这里用到一个函数OCIStmtSetPieceInfo(),设置数据片信息函数,看一下它的原型和参数。

sword OCIStmtSetPieceInfo ( void *hndlp,
    ub4             type,
    OCIError    *errhp,
    const void  *bufp,
    ub4            *alenp,
    ub1            piece,
    const void  *indp,
    ub2            *rcodep );

hndlp是一个输入/输出参数,要设置信息的句柄。可以是绑定句柄,也可以是定义句柄。查询的分片操作也要用到这个函数。

type是一个输入参数,是上面句柄的类型,OCI_HTYPE_BIND或者OCI_HTYPE_DEFINE。

errhp是一个输出参数,错误句柄,用于返回函数的错误码和错误信息文本。

bufp是一个输入/输出参数,数据缓冲区地址,绑定句柄是提供数据的地址,定义句柄是接收数据的地址。

alenp是一个输入/输出参数,数据的实际长度,绑定句柄是提供数据的长度,定义句柄是返回数据的长度。

indp是一个输入/输出参数,是指示变量,与OCIBindByPos()函数中一样。

rcodep是一个输入/输出参数,是字段级返回码,与OCIBindByPos()函数中一样。

假如我们创建一张表叫test_long_tab,然后向表中插入数据。建表语句为CREATE TABLE test_long_tab (ID NUMBER, NAME VARCHAR2(100), INFO LONG)。

我们下面看一个完整的例子,向LONG字段INFO中分片插入数据,一次数据片插入4000字符,插入10次。

OCIEnv		*envhp = NULL;
OCIError	*errhp = NULL;
OCIServer	*svrhp = NULL;
OCISession	*usrhp = NULL;
OCISvcCtx	*svchp = NULL;
OCIStmt		*smthp = NULL;
 
 
/* 插入分片的LONG数据 */
int insert_long_piece(void)
{
    sword	rc;
    int		slen;
    sb2		ind_info;
    ub4		alen_info;
    ub2		rcode_info;
    ub1     piece;
    OCIBind	*bndp;
    char	sqltxt[1024];
    char    long_buf[4096];
 
    /* 分配OCI语句句柄 */
    rc = OCIHandleAlloc(
        (void *)envhp,
        (void **)&smthp,
        OCI_HTYPE_STMT,
        0,
        (void **)NULL
    );
 
    if (rc != OCI_SUCCESS) {
        fprintf(stderr, "OCIHandleAlloc() - allocate statement handle error !\n");
        return (-1);
    }
 
    /* 生成SQL语句文本 */
    strcpy(sqltxt,
        "INSERT INTO test_long_tab (ID, NAME, INFO) VALUES (1, 'LONG DATA', :1)");
    slen = strlen(sqltxt);
 
    /* 准备语句 */
    if (check_oci_error(errhp,
        OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen,
            OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0)
        return (-1);
 
    /* 绑定第一个占位符INFO,使用OCI_DATA_AT_EXEC模式,value_sz要设置成插入数据的最大值 */
    if (check_oci_error(errhp,
        OCIBindByPos((OCIStmt *)smthp,
            (OCIBind **)&bndp,
            errhp,
            (ub4)1,	            /* position */
            (void *)NULL,       /* valuep */
            (sb4)40000,         /* value_sz */
            (ub2)SQLT_LNG,      /* dty */
            (void *)NULL,       /* indp */
            (ub2 *)NULL,        /* alenp */
            (ub2 *)NULL,        /* column return code pointer */
            (ub4)0,             /* maxarr_len */
            (ub4 *)NULL,        /* curelep */
            (ub4)OCI_DATA_AT_EXEC)
        ) < 0)
        return (-1);
 

    for (i=0; ; i++) { 
        /* 执行OCI语句 */
        if ((rc = check_oci_error(errhp,
            OCIStmtExecute(svchp,
                smthp,              /* stmthp */
                errhp,              /* errhp */
                1,                  /* iters */
                0,                  /* rowoff */
                NULL,               /* snap_in */
                NULL,               /* snap_out */
                OCI_DEFAULT)        /* mode */
            )) < 0)
            return (-1);

        if (rc == OCI_SUCCESS) {
            /* 插入数据片完毕,退出循环 */
            break;
        }

        if (rc != OCI_NEED_DATA) {
            fprintf(stderr, "data not completed !\n");
            return (-1);
        }

        /* 设置数据片类型 */
        if (i == 0)
            piece = OCI_FIRST_PIECE;
        else if (i == 9)
            piece = OCI_LAST_PIECE;
        else
            piece = OCI_NEXT_PIECE;

        /* 产生插入的数据,设置缓冲区和数据长度 */
        sprintf(long_buf, "%d", i);
        memset(&long_buf[1], 'a', 3999);
        alen_info = 4000;

        if (check_oci_error(errhp,
            OCIStmtSetPieceInfo((void *)bndp, OCI_HTYPE_BIND,
                errhp, (const void *)long_buf, &alen_info,
                piece, (const void *)&ind_info, &rcode_info)
            ) < 0)
            return (-1);
    }
 
    /* 提交改变的数据 */
    if (check_oci_error(errhp,
        OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0)
        return (-1);
 
    return (0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值