访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。
要插入LOB字段数据有多种办法,其中一种就是把LOB数据当做普通数据来处理,直接绑定变量,变量指向LOB数据,然后执行语句,就能插入数据。这时CLOB要用VARCHAR2类型绑定,BLOB用RAW类型绑定。这种方式适合插入小数据量的LOB数据,如果要插入大量的LOB数据(一般超过4000字节),就需要绑定LOB定位符,然后插入一个空的LOB定位符,随后通过LOB SELECT操作得到这个LOB的完整定位符信息,通过LOB的写函数,分批写入LOB数据。
先看看LOB定位符的绑定,使用OCIBindByPos()函数,绑定值是LOB定位符的指针,大小为定位符指针的大小sizeof(OCILobLocator *),其他参数与绑定别的字段类型相同。如果是绑定CLOB,操作如下。
OCILobLocator *locp;
OCIBindByPos((smthp,
(OCIBind **)&bndp,
errhp,
(ub4)1,
(void *)&locp,
(sb4)sizeof(OCILobLocator *),
(ub2)SQLT_CLOB,
(void *)NULL, /* indicator */
(ub2 *)NULL, /* alenp */
(ub2 *)NULL, /* column return code pointer */
(ub4)0, /* maxarr_len */
(ub4 *)NULL, /* curelep */
(ub4)OCI_DEFAULT);
执行LOB SELECT操作就要进行变量输出定义,用到OCIDefineByPos()函数,还以定义CLOB为例,操作如下。
OCILobLocator *locp;
OCIDefineByPos(smthp,
(OCIDefine **)&defp,
errhp,
(ub4)1,
(void *)&locp,
(sb4)sizeof(OCILobLocator *),
(ub2)SQLT_CLOB,
(void *)NULL,
(ub2 *)NULL,
(ub2 *)NULL,
(ub4)OCI_DEFAULT);
注意在绑定和定义函数中LOB定位符输入的都是定位符的地址,是一个指针的指针,千万不要用错了。
我们举一个例子,创建一个CLOB表叫做test_clob_tab,创建语句为CREATE TABLE test_clob_tab (ID NUMBER, MESSAGE CLOB)。然后向表中插入一条数据INSERT INTO test_clob_tab values (1, EMPTY_CLOB()),然后通过SELECT MESSAGE FROM test_clob_tab WHERE ID=1查询语句得到LOB的定位符。我们写一段程序通过OCI来实现上面的操作,这也是为后面向LOB字段中写入LOB数据做准备。
OCIEnv *envhp = NULL;
OCIError *errhp = NULL;
OCIServer *svrhp = NULL;
OCISession *usrhp = NULL;
OCISvcCtx *svchp = NULL;
OCIStmt *smthp = NULL;int insert_one_lob(void){sword rc;sb4 ec;int slen;sb2 ind_msg;ub2 alen_msg;ub4 lob_empty = 0;OCIBind *bndp;OCIDefine *defp;OCILobLocator *locp;char sqltxt[1024];text errbuf[512];strcpy(sqltxt, "INSERT INTO test_clob_tab (ID, MESSAGE) values (1, :1)");slen = strlen(sqltxt);rc = OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen,OCI_NTV_SYNTAX, OCI_DEFAULT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIStmtPrepare() - [%d] %s\n", ec, errbuf);return (-1);}/* 分配LOB定位符 */rc = OCIDescriptorAlloc((const void *)envhp, (void **)&locp,OCI_DTYPE_LOB, 0, (void **)NULL);if (rc != OCI_SUCCESS) {OCIErrorGet(envhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIDescriptorAlloc() - [%d] %s\n", ec, errbuf);return (-1);}/* 设置为空LOB */rc = OCIAttrSet((void *)(*locp), (ub4)OCI_DTYPE_LOB, (void *)&lob_empty, (ub4)0, (ub4)OCI_ATTR_LOBEMPTY, errhp);if (rc != OCI_SUCCESS) {OCIErrorGet(envhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIAttrSet() - [%d] %s\n", ec, errbuf);return (-1);}/* 绑定LOB定位符 */rc = OCIBindByPos((OCIStmt *)smthp,(OCIBind **)&bndp,errhp,(ub4)1,(void *)&locp,(sb4)sizeof(OCILobLocator *),(ub2)SQLT_CLOB,(void *)&ind_msg, /* indp */(ub2 *)&alen_msg, /* alenp */(ub2 *)NULL, /* column return code pointer */(ub4)0, /* maxarr_len */(ub4 *)NULL, /* curelep */(ub4)OCI_DEFAULT); /* mode */if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIBindByPos() - [%d] %s\n", ec, errbuf);return (-1);}ind_msg = 0;alen_msg = sizeof(OCILobLocator *);/* 执行语句 */rc = OCIStmtExecute(svchp,smthp, /* stmthp */errhp, /* errhp */1, /* iters */0, /* rowoff */NULL, /* snap_in */NULL, /* snap_out */OCI_DEFAULT); /* mode */if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIExecute() - [%d] %s\n", ec, errbuf);return (-1);}/* 提交改变 */rc = OCITransCommit(svchp, errhp, OCI_DEFAULT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCITransCommit() - [%d] %s\n", ec, errbuf);return (-1);}/* 下面执行LOB SELECT操作 */strcpy(sqltxt, "SELECT MESSAGE FROM test_clob_tab WHERE ID=1");slen = strlen(sqltxt);rc = OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen,OCI_NTV_SYNTAX, OCI_DEFAULT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIStmtPrepare() - [%d] %s\n", ec, errbuf);return (-1);}/* 定义LOB定位符输出 */rc = OCIDefineByPos((OCIStmt *)smthp,(OCIDefine **)&defp,(OCIError *)errhp,(ub4)1,(void *)&locp,(sb4)sizeof(OCILobLocator *),(ub2)SQLT_CLOB,(void *)&ind_msg,(ub2 *)&alen_msg,(ub2 *)NULL, /* column return code pointer */(ub4)OCI_DEFAULT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIDefineByPos() - [%d] %s\n", ec, errbuf);return (-1);}/* 执行语句 */rc = OCIStmtExecute(svchp,smthp, /* stmthp */errhp, /* errhp */0, /* iters */0, /* rowoff */NULL, /* snap_in */NULL, /* snap_out */OCI_DEFAULT); /* mode */if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIExecute() - [%d] %s\n", ec, errbuf);return (-1);}/* 执行fetch操作 */rc = OCIStmtFetch(smthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIStmtFetch() - [%d] %s\n", ec, errbuf);return (-1);}/* 至此,ID=1的记录中的LOB字段的LOB定位符就存储在了locp指针中了* 后面,就可以通过这个定位符写入数据了* 从上面的代码也看到,要写入LOB数据,之前的操作很繁琐*//* 释放LOB定位符 */rc = OCIDescriptorFree((void *)locp, OCI_DTYPE_LOB);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCIDescriptorFree() - [%d] %s\n", ec, errbuf);return (-1);}return (0);
}
从上面的代码看到在插入空LOB到写入LOB数据之前,要经过很繁琐的操作,当你真正写一段能跑起来的代码不能说象噩梦,至少也够头疼的,有没有办法把这个过程变得简洁一些,省去这些繁琐的代码呢?OCI提供了你想要的一切功能,只要你能想到好的办法,编程永远是思想比代码重要,后面我们会介绍一种节约代码的方法。