当前位置: 首页 > news >正文

OCI编程高级篇(八) LOB写操作

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

上一节我们介绍了LOB定位符的绑定和定义操作,这里重点强调一下定义操作,这个行为一般用于LOB SELECT操作,LOB SELECT操作是所有LOB操作的基础,所有的关于LOB操作的OCI函数都是针对LOB定位符的,LOB SELECT的目的就是为了得到一个LOB定位符,一个LOB表的每行数据的每个LOB字段都对应一个LOB定位符,所以处理一行数据的多个LOB字段也要得到多个LOB定位符。下面看看LOB写操作的步骤。

1. 准备LOB SELECT语句,一般SQL语句文本为SELECT lob_column FROM lob_table WHERE XXXX=XXXX FOR UPDATE

2. 定义输出的LOB定位符。这个定位符在之前要分配好,不用设置为空LOB

3. 执行LOB SELECT语句。

4. 执行OCIStmtFetch()操作,把LOB定位符和LOB字段关联起来。

5. 打开LOB定位符,使用OCILobOpen()函数。

6. 写入LOB数据,可以循环写入多次LOB数据,使用OCILobWrite2()函数。

7. 关闭LOB定位符,使用OCILobClose()函数。

8. 提交数据库改变。

先看看用到的OCI函数原型和参数。

打开LOB函数。

sword OCILobOpen ( OCISvcCtx *svchp,
    OCIError           *errhp,
    OCILobLocator *locp,
    ub1                    mode );

svchp是一个输入参数,是OCI服务上下文句柄。

errhp是一个输入/输出参数,错误句柄,用于返回错误码和错误信息文本。

locp是一个输入/输出参数,需要打开的LOB定位符。

mode是一个输入参数,打开的方式,取值OCI_LOB_READONLYOCI_LOB_READWRITE

关闭LOB函数。

sword OCILobClose ( OCISvcCtx *svchp,
    OCIError           *errhp,
    OCILobLocator *locp );

svchp是一个输入参数,是OCI服务上下文句柄。

errhp是一个输入/输出参数,错误句柄,用于返回错误码和错误信息文本。

locp是一个输入/输出参数,需要关闭的LOB定位符。

LOB函数。

sword OCILobWrite2 ( OCISvcCtx *svchp,
    OCIError           *errhp,
    OCILobLocator *locp,
    oraub8              *byte_amtp,
    oraub8              *char_amtp,
    oraub8              offset,
    void                   *bufp,
    oraub8               buflen,
    ub1                    piece,
    void                   *ctxp,
    OCICallbackLobWrite2 (cbfp)
    (
        void     *ctxp,
        void     *bufp,
        oraub8 *lenp,
        ub1      *piecep
        void      **changed_bufpp,
        oraub8 *changed_lenp
    )
    ub2                    csid,
    ub1                    csfrm );

svchp是一个输入/输出参数,是OCI服务上下文句柄。

errhp是一个输入/输出参数,错误句柄,用于返回错误码和错误信息文本。

locp是一个输入/输出参数,需要操作的LOB定位符,唯一引用一个LOB

byte_amtp是一个输入/输出参数,写入LOB的字节数,在BLOB写入时使用。

char_amtp是一个输入/输出参数,写入LOB的字符个数,在CLOB写入时使用,BLOB写入时忽略这个参数。

offset是一个输入参数,写入LOB的绝对偏移量,从LOB头开始计算。对CLOB计算单位是字符,对BLOB计算单位是字节。offset的位置从1开始计算。如果使用流写入方式,只需要在第一次调用写函数时设置offset值,后续的写函数可以忽略offset,函数会自动判断。

bufp是一个输入参数,是写入的LOB数据的缓冲区指针。

buflen是一个输入参数,表示LOB数据缓冲区中数据的大小,以字节计算。

piece是一个输入参数,表示写入的是哪个数据片。取值为OCI_ONE_PIECE,流模式中为OCI_FIRST_PIECEOCI_NEXT_PIECEOCI_LAST_PIECE

ctxp是一个输入参数,是回调函数的上下文指针,可以设置为NULL

cbfp是一个输入参数,是回调函数的函数指针,不使用回调函数设置为NULL

csid是一个输入参数,是缓冲区中数据的字符集ID,只对CLOB起作用。

csfrm是一个输入参数,是缓冲区数据的字符集形式,取值SQLCS_IMPLICIT表示与数据库字符集一致,取值SQLCS_NCHAR表示使用国际字符集。

我们使用上一节中创建的表test_clob_tab,里面已经插入一条空LOB数据,现在看看怎样写入LOB数据,我们向LOB中写入20次,每次写入4000字符,使用流模式写入。代码如下。

 

OCIEnv        *envhp = NULL;
OCIError    *errhp = NULL;
OCIServer    *svrhp = NULL;
OCISession    *usrhp = NULL;
OCISvcCtx    *svchp = NULL;
OCIStmt        *smthp = NULL;​​int write_to_lob(void){int              i;sword            rc;sb4              ec;ub1              piece;int              slen;oraub8           amt;OCIDefine        *defp;OCILobLocator    *locp;char             sqltxt[1024];text             errbuf[512];char             buf[4096];/* 分配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 SELECT操作 */strcpy(sqltxt, "SELECT MESSAGE FROM test_clob_tab WHERE ID=1 FOR UPDATE");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 *)NULL,(ub2 *)NULL,(ub2 *)NULL,(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);}/* 打开LOB */rc = OCILobOpen(svchp, errhp, locp, OCI_LOB_READWRITE);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCILobOpen() - [%d] %s\n", ec, errbuf);return (-1);}for (i=0; i<20; i++) {if (i == 0)piece = OCI_FIRST_PIECE;else if (i == 19)piece = OCI_LAST_PIECE;elsepiece = OCI_NEXT_PIECE;sprintf(buf, "%02d", i);memset(&buf[2], 3998, 'A');amt = 4000;rc = OCILobWrite2(svchp, errhp, locp, NULL, &amt, 1,buf, 4000, piece, 0, SQLCS_IMPLICIT);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCILobWrite2() - [%d] %s\n", ec, errbuf);return (-1);}}/* 关闭LOB */rc = OCILobClose(svchp, errhp, locp);if (rc != OCI_SUCCESS) {OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR);fprintf(stderr, "OCILobClose() - [%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定位符 */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);
}

 

在上面的写入中使用了流模式,在第一次写入时使用OCI_FIRST_PIECE,最后一次写入使用OCI_LAST_PIECE,其他的写入使用OCI_NEXT_PIECE,只需要在第一次写入时指定写入偏移量1,就可以从头写入数据,后续写操作的偏移量都被忽略了。写入函数的csid设置为0,数据使用环境变量NLS_LANG定义的字符集。

如果不使用流模式写入,那么写入操作使用OCI_ONE_PIECE,每次写入一片数据,每次要自己计算偏移量的位置,好处是可以随机向任意位置写入数据。

在写数据前要打开LOB,写完后要关闭LOB,跟写一个文件相似。如果不打开LOB也可以直接调用写函数,不过每次写操作Oracle还是会隐式的打开LOB,写完一次后隐式关闭LOB,这样在大量多次写入时会影响效率,所以在写之前打开LOB是一个好习惯。

 

http://www.sczhlp.com/news/11862/

相关文章:

  • OCI编程高级篇(九) LOB读操作
  • 配置nginx目录游览功能
  • 博客园众包:再次诚征3D影像景深延拓实时处理方案(预算8
  • 爬虫-Day1
  • HTML
  • CSS3
  • nginx获取真实IP详解
  • linux 17安装失败,ensp路由器AR启动失败求解
  • OCI编程高级篇(六) LOB定位符
  • 老君山
  • OCI编程高级篇(四) 分片插入
  • 生成 OneWeb 兼容信号以进行接收机测试
  • OCI编程高级篇(五) 分片查询
  • 2025年材料腐蚀与防护国际学术研讨会(ISMCP 2025)
  • 在多邻国学日语的一些笔记整理
  • OCI编程高级篇(三) 批量执行
  • NebulaGraph 的数据分布方式总结
  • 8月14号
  • AI女友涉黄传播被捕,我们离“赛博深渊”还有多远?
  • 格式化日期方法
  • 浅谈: 最短路径算法 Dijkstra 中令人困惑的地方
  • 乐观锁悲观锁分布式锁消息队列
  • OCI编程基础篇(九) 查询数据
  • rust学习笔记之小练习:泛型、trait
  • 线程中并发的安全面试题
  • 法国农业部如何利用Elastic技术监控商业捕鱼业
  • 机械手弧焊电源气体流量优化方法
  • nginx配置https访问
  • CSP-J/S资源链接1
  • nvm 报错 The system cannot find the file specified