访问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提供了你想要的一切功能,只要你能想到好的办法,编程永远是思想比代码重要,后面我们会介绍一种节约代码的方法。