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