访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。

 当插入表中的一个字段,数据量比较大时怎么处理呢?我们在前面介绍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;elsepiece = 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);
}