OCI编程高级篇(四) 分片插入
访问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; 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); }

浙公网安备 33010602011771号