LOB大对象操作¶
ACI包括一组用于对数据库中的大对象(LOB)执行操作的功能。持久性LOB(BLOB,CLOB)以优化空间并提供有效访问的方式存储在数据库表空间中。 这些LOB具有数据库的全面事务支持。 BFILE是存储在数据库表空间之外的服务器操作系统文件中的大型数据对象。
ACI还提供对临时LOB的支持,这些LOB可以像本地变量一样用于对LOB数据进行操作。
大对象读操作可以调用 ACILobRead 来完成,写操作可以调用 ACILobWrite 来完成,例如,对于内容为“Hello World!”的CLOB型数据,当调用 ACILobWrite 并传入偏位移参数值为7,写入内容为“"I am a new string”时,CLOB的内容将会更新为“Hello I am a new string”,大对象获取长度操作可以调用 ACILobGetLength 来完成。
BFILE是只读的,数据库仅支持二进制BFILE。
LOB的创建¶
LOB可以是持久性的(存储在数据库中),也可以是临时性的(仅存在于应用程序范围内)。
有两种创建和修改持久性LOB的方法:
方法1:使用数据接口
通过将字符数据直接插入到CLOB列中或将数据直接插入到BLOB列中来创建LOB,数据库后台会自动创建一个永久的lob大对象。还可以使用SQL UPDATE语句修改LOB,将字符数据绑定到CLOB列或将RAW数据绑定到BLOB列。
该数据接口仅支持最大2 GB-1的数据大小,是sb4数据类型的最大大小。
方法2:使用LOB定位器
通过使用 ACIDescriptorAlloc 初始化新的LOB定位器,调用 ACIAttrSet 将其设置为空(使用ACI_ATTR_LOBEMPTY属性),然后在INSERT语句中将定位器绑定到占位符,可以创建新的内部LOB。 这样做会将空的定位器插入具有LOB列或属性的表中。 然后,您可以在此行上执行SELECT ... FOR UPDATE操作以获取定位器,并使用ACI LOB函数之一对其进行写入。
备注:若要修改LOB列或属性(写入,复制,修剪等),必须锁定包含LOB的行。 一种方法是在执行操作之前使用SELECT ... FOR UPDATE语句选择定位器。
为了使任何LOB写入命令成功执行,必须打开一个事务。 如果在写入数据之前提交事务,则必须再次锁定该行(例如,通过重新发出SELECT ... FOR UPDATE语句),因为提交会关闭事务。
LOB的类型¶
数据库中的Lob支持BLOB、CLOB、BFILE三种类型,获得一个loblocator地址后,可以获得这个loblocator是什么类型的LOB,通过ACI_ATTR_LOB_TYPE属性获得ACILobLocator描述符的LOB类型,类型包括:SQLT_BLOB、SQLT_CLOB、SQLT_BFILEE。
r = ACIAttrGet(clob, ACI_DTYPE_LOB, (void **)&lobtype, 0, ACI_ATTR_LOB_TYPE, m_perr);
同时还可以获得LOB是否是临时大对象,还是持久大对象,通过: ACILobIsTemporary 函数获得:
boolean is_temporary = FALSE;
r = ACILobIsTemporary(m_penv, m_perr, clob, &is_temporary);
BFILE文件操作¶
在INSERT语句中使用BFILENAME函数,以将外部服务器端(操作系统)文件与表中的BFILE列或属性相关联。
在UPDATE语句中使用BFILENAME会将BFILE列或属性与其他操作系统文件相关联。 ACILobFileSetName 也可用于将表中的BFILE与操作系统文件相关联。 BFILENAME函数通常用于不带绑定变量的INSERT或UPDATE语句中,而 ACILobFileSetName 用于绑定变量。
LOB/BFILE操作¶
在所有涉及到数据偏移量的LOB操作中,偏移量都从1开始。对于LOB操作(例如 ACILobCopy2 , ACILobErase2 , ACILobLoadFromFile2 和 ACILobTrim2 ),amount参数以字符表示CLOB ,而不考虑客户端字符集。
这些LOB操作LOB数据,当客户端字符集的宽度不同时,以下一般规则适用于LOB调用中的数量和偏移量参数:
amount-当数量参数参照服务器端LOB时,数量以字符为单位。 当数量参数参照客户端缓冲区时,数量以字节为单位。
offset-不管客户端字符集是否为宽度可变,offset参数对于CLOB始终以字符为单位,对于BLOB或BFILEs始终以字节为单位。
您可以为CLOB列绑定或定义字符数据,或者为BLOB列绑定或定义binary数据。与传统的LOB接口需要多次往返相比,这仅需要一次往返即可插入或选择LOB。
LOB接口扩展¶
ACI提供了一套以“ 2”结尾并且使用数据类型aciub8代替数据类型ub4的函数,比如: ACILobRead2 , ACILobWrite2 和 ACILobWriteAppend2 ,主要解决以下问题:
问题1:参数amtp根据定位器类型和字符集返回字节或字符长度。这很复杂,用户没有灵活性来根据他们的要求使用字节长度或字符长度。
解决办法:读/写调用应同时使用byte_amtp和char_amtp参数来代替amtp参数。对于CLOB,首选使用char_amtp参数,并且只有在char_amtp为零时,才将byte_amtp参数视为输入。在CLOB的输出上,byte_amtp和char_amtp参数都被填充。对于BLOB和BFILE,输入和输出均忽略char_ampt参数。
问题2:对于 ACILobRead2 ,没有用于指示轮询模式的标志。用户没有简单的方法说“我有一个100字节的缓冲区。请尽可能多地填充它。”以前,他们必须估算要指定多少个字符。如果他们猜得太多,就会无意间被迫进入轮询模式。因此,用户代码可能陷入轮询模式,并且随后的ACI调用都被阻止。
解决办法:此调用应该作为输入参数,并且如果传递ACI_ONE_PIECE,则应尽可能填充缓冲区并发出,即使byte_amtp参数或char_amtp参数指示的数量大于缓冲区长度也是如此。 bufl的值用于指定要读取的最大字节数。
问题3:在轮询模式下调用LOB写操作后,用户直到轮询结束才知道实际获取了多少个字符或字节。
解决方案:在轮询模式下的每次调用之后,必须同时更新byte_amtp和char_amtp参数。
问题4:在具有回调的流模式下读取或写入数据时,用户必须为每个数据使用相同的缓冲区。
解决方案:回调函数必须具有两个新参数以提供缓冲区和缓冲区长度。 回调函数可以将buffer参数设置为NULL,以遵循旧的行为:对所有片段使用第一次调用中传递的默认缓冲区。
LOB关闭¶
ACI提供了一些函数来显式打开大对象 ACILobOpen ,关闭大对象 ACILobClose 以及测试大对象是否已打开 ACILobIsOpen 。这些功能标记了一系列LOB操作的开始和结束,以便在LOB关闭时可以执行特定的处理,例如更新索引。
LOB定位器不存储有关LOB状态的任何信息。一个以上的定位器可能指向同一打开的LOB。但是,对于BFILE,打开状态与特定的定位器相关联。因此,可以使用不同的定位符在同一个BFILE上执行多个打开调用。
如果应用程序没有在一组 ACILobOpen 和 ACILobClose 调用中包装LOB操作,则对LOB的每次修改都会隐式打开和关闭LOB,从而触发与LOB更改相关的任何触发器。
如果在打开和关闭调用中未包装LOB操作,则在进行LOB修改时会更新LOB上的任何可扩展索引,因此该索引始终有效并且可以随时使用。如果在一组 ACILobOpen 和 ACILobClose 调用中修改了LOB,则不会为单个LOB修改触发触发器。触发器仅在 ACILobClose 调用之后才触发,因此索引直到close调用之后才更新,因此在open和close调用中无效。 ACILobIsOpen 可以与内部LOB和BFILE一起使用。
在关闭事务时打开的LOB没有关闭,将返回错误。返回错误后,LOB不再标记为已打开,但事务已成功提交,因此,将提交对事务中的LOB和非LOB数据所做的所有更改。
没有事务时,打开的LOB必须在会话结束之前关闭。如果在会话结束时有LOB打开,则该LOB不再标记为打开。
开启和关闭LOB的限制¶
LOB的打开和关闭机制具有以下限制:
提交事务之前,应用程序必须关闭所有先前打开的LOB。 否则,将导致错误。 如果回滚事务,则所有打开的LOB以及所做的更改都将被丢弃。 因为没有关闭LOB,所以不会触发关联的触发器。
尽管打开的内部LOB的数量没有限制,但是由操作系统等参数是有限制的。 将已经打开的定位器分配给另一个定位器不算作打开新的LOB。
在同一事务中使用不同的定位器或相同的定位器两次打开或关闭相同的内部LOB是错误的。
关闭尚未打开的LOB是错误的。
临时大对象支持¶
ACI提供用于创建和释放临时LOB的函数 ACILobCreateTemporary 和 ACILobFreeTemporary ,以及用于确定LOB是否为临时的函数 ACILobIsTemporary 。
临时LOB不会永久存储在数据库中,而是像对LOB数据进行操作的局部变量一样起作用。 在标准(持久)LOB上运行的ACI功能也可以在临时LOB上使用。
与持久性LOB一样,所有功能都在临时LOB的定位器上运行,并且实际的LOB数据通过定位器进行访问。
临时LOB定位器可用作以下类型的SQL语句的参数:
- 更新-临时LOB定位器可以用作WHERE子句中的值,也可以用作函数的参数。 定位符也可以在SET子句中使用。
- DELETE-可以在WHERE子句中使用临时LOB定位符,也可以将其用作函数的参数。
- SELECT-可以在WHERE子句中使用临时LOB定位符,也可以将其用作函数的参数。 选择函数的返回值时,临时LOB还可在SELECT ... INTO语句中用作返回变量。
创建临时大对象¶
使用 ACILobCreateTemporary 函数创建一个临时LOB。默认持续时间是当前会话的持续时间。 在持续时间结束时,将删除所有临时LOB。 用户可以通过使用 ACILobFreeTemporary 函数显式释放临时LOB来回收临时LOB空间。 临时LOB在创建时为空。
要使一个临时LOB永久化,请使用 ACILobCopy2 将数据从该临时LOB复制到一个永久LOB中。 还可以将INSERT语句的VALUES子句中的临时LOB用作UPDATE语句中分配的源,或将其分配给持久性LOB属性,然后刷新该对象。 可以使用与标准LOB相同的功能来修改临时LOB。
释放临时大对象¶
每当您的ACI程序从SQL或PL / SQL获取LOB定位器时,请使用 ACILobIsTemporary 函数检查该定位器是否是临时的。
如果是临时大对象,则使用 ACILobFreeTemporary 调用释放定位器。 定位器可以在选择或外绑定期间来自定义。 临时LOB生命周期为会话持续时间。 在下一行的定位器覆盖定位器之前,应用程序必须执行以下操作:
ACILobIsTemporary(env, err, locator, is_temporary);
if(is_temporary)
ACILobFreeTemporary(svc, err, locator);
LOB指针分配注意事项¶
在重新使用绑定变量执行SQL语句之前,必须使用 ACILobFreeTemporary 调用释放现有绑定LOB定位器缓冲区中的任何临时LOB;
指针分配创建LOB的浅拷贝,指针分配后,源和目标LOB指向同一数据副本。 此行为不同于使用LOB API(例如 ACILobLocatorAssign )执行分配。 使用API时,定位器在分配后逻辑上指向数据的独立副本;
对于临时LOB,在分配指针之前,必须确保 ACILobFreeTemporary 释放目标LOB定位器中的任何临时LOB。使用 ACILobLocatorAssign 时,原始临时LOB在目标LOB定位器变量中的,如果有的话,在分配发生之前将其释放。
临时大对象操作示例¶
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aci.h>
static void checkerr (/*_ ACIError *errhp, sword status _*/);
/* 这个函数读取一个视频文件从print_media 表中,首先创建一个临时lob*/
sb4 select_and_createtemp (ACILobLocator *lob_loc,
ACIError *errhp,
ACISvcCtx *svchp,
ACIStmt *stmthp,
ACIEnv *envhp)
{
ACIDefine *defnp1;
ACIBind *bndhp;
text *sqlstmt;
int rowind =1;
ub4 loblen = 0;
ACILobLocator *tblob;
if(ACIDescriptorAlloc((void*)envhp, (void **)&tblob,
(ub4)ACI_DTYPE_LOB, (size_t)0, (void**)0))
{
printf("ACIDescriptor 调用失败 \n");
return ACI_ERROR;
}
/* 查询Clip_ID =1 */
sqlstmt=(text *)"SELECT Frame FROM print_media WHERE product_ID = 1 FOR UPDATE";
if (ACIStmtPrepare2(svchp, stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt),
NULL, 0, (ub4) ACI_NTV_SYNTAX, (ub4) ACI_DEFAULT))
{
(void) printf("失败: ACIStmtPrepare2 语句\n");
return ACI_ERROR;
}
/* 定义lob列 */
if (ACIDefineByPos(stmthp, &defnp1, errhp, (ub4)1, (void *) &lob_loc, (sb4)0,
(ub2) SQLT_BLOB, (void *)0, (ub2 *)0, (ub2 *)0, (ub4) ACI_DEFAULT))
{
(void) printf("失败: ACIDefineByPos语句\n");
return ACI_ERROR;
}
/* 执行查询或获取一条数据*/
if (ACIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(CONST ACISnapshot*) 0, (ACISnapshot*) 0, (ub4) ACI_DEFAULT))
{
(void) printf("失败:ACIStmtExecute语句\n");
return ACI_ERROR;
}
if(ACILobCreateTemporary(svchp, errhp, tblob, (ub2)0, SQLCS_IMPLICIT,
ACI_TEMP_BLOB, ACI_ATTR_NOCACHE, ACI_DURATION_SESSION))
{
(void) printf("失败: CreateTemporary语句\n");
return ACI_ERROR;
}
if (ACILobGetLength(svchp, errhp, lob_loc, &loblen) != ACI_SUCCESS)
{
printf("ACILobGetLength失败\n");
return ACI_ERROR;
}
if (ACILobCopy(svchp, errhp, tblob,lob_loc,(ub4)loblen, (ub4) 1, (ub4) 1))
{
printf( "ACILobCopy失败\n");
}
if(ACILobFreeTemporary(svchp,errhp,tblob))
{
printf ("失败: ACILobFreeTemporary 调用\n");
return ACI_ERROR;
}
return ACI_SUCCESS;
}
int main(char *argv, int argc)
{
/* ACI 句柄 */
ACIEnv *envhp;
ACIServer *srvhp;
ACISvcCtx *svchp;
ACIError *errhp;
ACISession *authp;
ACIStmt *stmthp;
ACILobLocator *clob, *blob;
ACILobLocator *lob_loc;
int type =1;
ACIEnvCreate(&envhp, ACI_DEFAULT, (void *)0, 0, 0, 0,
(size_t)0, (void *)0);
(void) ACIHandleAlloc( (void *) envhp, (void **) &errhp, ACI_HTYPE_ERROR, (size_t) 0, (void **) 0);
(void) ACIHandleAlloc( (void *) envhp, (void **) &srvhp, ACI_HTYPE_SERVER, (size_t) 0, (void **) 0);
(void) ACIHandleAlloc( (void *) envhp, (void **) &svchp, ACI_HTYPE_SVCCTX, (size_t) 0, (void **) 0);
(void) ACIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0);
(void) ACIAttrSet ((void *) svchp, ACI_HTYPE_SVCCTX, (void *)srvhp, (ub4) 0, ACI_ATTR_SERVER, (ACIError *) errhp);
(void) ACIHandleAlloc((void *) envhp, (void **)&authp, (ub4) ACI_HTYPE_SESSION, (size_t) 0, (void **) 0);
(void) ACIAttrSet((void *) authp, (ub4) ACI_HTYPE_SESSION,(void *) "scott", (ub4)5, (ub4) ACI_ATTR_USERNAME, errhp);
(void) ACIAttrSet((void *) authp, (ub4) ACI_HTYPE_SESSION, (void *) "password", (ub4) 5, (ub4) ACI_ATTR_PASSWORD, errhp);
checkerr(errhp, ACISessionBegin ( svchp, errhp, authp,ACI_CRED_RDBMS, (ub4) ACI_DEFAULT));
(void) ACIAttrSet((void *) svchp, (ub4) ACI_HTYPE_SVCCTX,(void *) authp, (ub4) 0, (ub4) ACI_ATTR_SESSION, errhp);
/* ------- 完成登录 ----------------------------------*/
checkerr(errhp, ACIHandleAlloc( (void *) envhp, (void **) &stmthp,
ACI_HTYPE_STMT, (size_t) 0, (void **) 0));
checkerr(errhp, ACIDescriptorAlloc((void *)envhp, (void **)&lob_loc,
(ub4) ACI_DTYPE_LOB, (size_t) 0, (void **) 0));
printf("调用select_and_createtemp\n");
select_and_createtemp (lob_loc, errhp, svchp,stmthp,envhp);
return 0;
}
void checkerr(errhp, status)
ACIError *errhp;
sword status;
{
text errbuf[512];
sb4 errcode = 0;
switch (status)
{
case ACI_SUCCESS:
break;
case ACI_SUCCESS_WITH_INFO:
(void) printf("Error - ACI_SUCCESS_WITH_INFO\n");
break;
case ACI_NEED_DATA:
(void) printf("Error - ACI_NEED_DATA\n");
break;
case ACI_NO_DATA:
(void) printf("Error - ACI_NODATA\n");
break;
case ACI_ERROR:
(void) ACIErrorGet((void *)errhp, (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), ACI_HTYPE_ERROR);
(void) printf("Error - %.*s\n", 512, errbuf);
break;
case ACI_INVALID_HANDLE:
(void) printf("Error - ACI_INVALID_HANDLE\n");
break;
case ACI_STILL_EXECUTING:
(void) printf("Error - ACI_STILL_EXECUTE\n");
break;
case ACI_CONTINUE:
(void) printf("Error - ACI_CONTINUE\n");
break;
default:
break;
}
}
LOB数据预取¶
ACI在查询LOB列时,返回的是LOB的地址,并不返回真实数据,如果在通过 ACILobRead 等方法对LOB数据读取时,ACI会用LOB地址再次发送请求给数据库端返回数据,这样的操作常规来说没有问题,但对于一次查询上万行LOB数据的场景(且合格LOB数据都比较小,几百K),每获取一条LOB数据都会与数据库服务端做二次或者多次交互,导致获取效率非常低。因此ACI设计了LOB预取机制,来提高大对象的读取效率。
预取会占用内存,预取大小对内存占用有决定性影响,因此LOB预取功能,需要对LOB数据有充分了解的人进行合理使用。建议对大部分LOB数据小于1M的数据进行缓存,而LOB普遍大于1M的,不建议使用LOB缓存。LOB预取功能只在性能上有所差异,不对LOB数据产生任何影响。
预取实现方式¶
通过设置session句柄的ACI_ATTR_DEFAULT_LOBPREFETCH_SIZE设置当前session所有lob获取时都进行预取大小,默认值为0,代表不预取。
通过设置define句柄的ACI_ATTR_LOBPREFETCH_LENGTH属性设置当前列是否预取;
通过设置define句柄的ACI_ATTR_LOBPREFETCH_SIZE属性修改当前列的预取长度,如果不设置,继承session句柄的ACI_ATTR_DEFAULT_LOBPREFETCH_SIZE属性值。
LOBPREFETCH_SIZE对于BLOB来说,是按字节返回;对于CLOB来说是按字节返回;
对于不用loblocator方式去获取LOB数据时,如果有预取,将预取的数据直接放到定义的缓存中去。
ACI_ATTR_DEFAULT_LOBPREFETCH_SIZE/ACI_ATTR_LOBPREFETCH_SIZE属性的最大长度为2147483647字节。
预取内存分配机制¶
在获取LOB定位器时分配描述符的预取缓存缓冲区,分配的缓冲区大小由用于定义句柄的ACI_ATTR_LOBPREFETCH_SIZE属性确定,此属性的默认值由会话句柄的ACI_ATTR_DEFAULT_LOBPREFETCH_SIZE属性值指示。如果已经分配了缓存缓冲区,则可以根据需要调整其大小。
对于以下两个LOB API,如果源定位器已缓存数据,则将分配目标定位器缓存或调整其大小,然后将缓存的数据从源复制到目标:
分配后,释放描述符本身时,将释放该描述符的高速缓存缓冲存储器。
预取失效机制¶
使用定位器更新LOB数据时,LOB描述符的缓存无效。这意味着缓存不再用于读取数据,并且定位器上的下一个 ACILobRead2 调用将进行往返。
以下LOBAPI使使用的描述符的预取缓存无效:
ACILobErase(不推荐使用)
ACILobTrim(不推荐使用)
ACILobWrite(不推荐使用)
ACILobWriteAppend(不推荐使用)
ACILobCopy(不推荐使用)
ACILobLoadFromFile(不推荐使用)
数据库服务器预取配置¶
数据库服务器端参数配置文件中支持对LOB预取的支持,如果设置了数据库参数LOB_PREFETCH_SIZE,ACI中没有对预取参数进行设置,ACI一样会进行大对象预取。
LOB操作示例¶
表定义:tabLob(id int, col_clob clob, col_blob blob)。
大对象读写操作¶
这种方式是通过查询的方式,将数据库中的大对象返回一个lob指针,通过返回lob指针进行大对象的读写。
#include <stdio.h>
#include <stdlib.h>
#include "aci.h"
#define LOB_BUFF_LEN 512 /*要操作的大对象buff长度*/
/*要插入的记录*/
typedef struct tagInsRecord
{
int in_int;
char in_varchar[64];
}InsRecord;
ACIEnv* env = NULL;
ACIError* err = NULL;
ACIServer* srv = NULL;
ACISvcCtx* svc = NULL;
ACISession* ses = NULL;
ACIStmt* stmt = NULL;
ACIBind* pBind[10];
ACIDefine* pDef[10];
char *dblink = "localhost:2003/osrdb";
char *dbuser = "SYSDBA";
char *dbpwd = "szoscar55";
void read_lob;//大对象读操作
void write_getlength_lob;//大对象写操作与获取长度
void checkerr(ACIError* err, sword status)
{
text errbuf[512];
ub4 buflen = 0;
sb4 errcode;
switch (status)
{
case ACI_SUCCESS:
break;
case ACI_SUCCESS_WITH_INFO:
ACIErrorGet ( err, (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), (ub4) ACI_HTYPE_ERROR);
printf("Error - ACI_SUCCESS_WITH_INFO:%sn", errbuf);
exit(-1);
break;
case ACI_NEED_DATA:
printf("Error - ACI_NEED_DATAn");
exit(-1);
break;
case ACI_NO_DATA:
printf("Error - ACI_NO_DATAn");
exit(-1);
break;
case ACI_ERROR:
ACIErrorGet ( err, (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), (ub4) ACI_HTYPE_ERROR);
printf("Error - %d %sn", errcode, errbuf);
exit(-1);
break;
case ACI_INVALID_HANDLE:
printf("Error - ACI_INVALID_HANDLEn");
exit(-1);
break;
case ACI_STILL_EXECUTING:
printf("Error - ACI_STILL_EXECUTEn");
exit(-1);
break;
case ACI_CONTINUE:
printf("Error - ACI_CONTINUEn");
exit(-1);
break;
default:
break;
}
}
int main(int args, char *argv[])
{
sword r = 0;
//初始化环境句柄
r = ACIInitialize(ACI_DEFAULT, NULL, NULL, NULL, NULL);
checkerr(err, r);
r = ACIEnvInit(&env, ACI_DEFAULT, 0, 0);
checkerr(err, r);
//分配并初始化各类应用句柄
r = ACIHandleAlloc(env, (void**)&err, ACI_HTYPE_ERROR, 0, 0);
checkerr(err, r);
r = ACIHandleAlloc(env, (void**)&srv, ACI_HTYPE_SERVER, 0, 0);
checkerr(err, r);
r = ACIHandleAlloc(env, (void**)&svc, ACI_HTYPE_SVCCTX, 0, 0);
checkerr(err, r);
r = ACIHandleAlloc(env, (void**)&ses, ACI_HTYPE_SESSION, 0, 0);
checkerr(err, r);
//连接数据库
r =ACIServerAttach(srv, err, (const OraText *)dblink, (dblink != NULL ?
(sb4)strlen(dblink):0), ACI_DEFAULT);
checkerr(err, r);
r = ACIAttrSet(svc, ACI_HTYPE_SVCCTX, srv, sizeof(srv),
ACI_ATTR_SERVER, err);
checkerr(err, r);
r = ACIAttrSet(ses, ACI_HTYPE_SESSION, dbuser, (ub4)strlen(dbuser),
ACI_ATTR_USERNAME, err);
checkerr(err, r);
r = ACIAttrSet(ses, ACI_HTYPE_SESSION, dbpwd, (ub4)strlen(dbpwd),
ACI_ATTR_PASSWORD, err);
checkerr(err, r);
r = ACISessionBegin(svc, err, ses, ACI_CRED_RDBMS, ACI_DEFAULT);
checkerr(err, r);
r = ACIAttrSet(svc, ACI_HTYPE_SVCCTX, ses, sizeof(ses),
ACI_ATTR_SESSION, err);
checkerr(err, r);
//分配语句句柄
r = ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0, 0);
checkerr(err, r);
//读lob
read_lob;
//写lob,并获取长度
write_getlength_lob;
return 0;
}
void read_lob
{
char *inCLobSql = "insert into tabLob(col_clob) values('我是中国人')";
char *selCLobSql = "select col_clob from tabLob";
ACILobLocator *clob;
char szV[50] ={0};
long lFileLen=0;
int readedlen = 0;
sword r = 0;
//插入clob数据
r = ACIHandleAlloc(env,(void**)&stmt,ACI_HTYPE_STMT,0,0);
checkerr(err, r);
r = ACIStmtPrepare(stmt,err,(const
OraText*)inCLobSql,(ub4)strlen(inCLobSql),
ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc,stmt,err,1,0,0,0,ACI_COMMIT_ON_SUCCESS);
checkerr(err, r);
//获取clob数据
r = ACIDescriptorAlloc(env,(void
**)&clob,ACI_DTYPE_LOB,0,NULL); /*clob描述符初始化*/
checkerr(err, r);
r = ACIStmtPrepare(stmt,err,(const OraText*)selCLobSql,(ub4)strlen(selCLobSql),ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIDefineByPos(stmt,&pDef[3],err,1,&clob,sizeof(clob),
SQLT_CLOB,0,0,0,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc,stmt,err,1,0,0,0,ACI_DEFAULT);
checkerr(err, r);
//读取clob数据
while (ACILobRead(svc, err, clob, (ub4*)&lFileLen, 1, szV+readedlen,
sizeof(szV), 0, 0, 0, 0) == ACI_NEED_DATA)
{
readedlen += lFileLen;
lFileLen = 0;
}
printf("读取到的clob数据为:%sn", szV);
r = ACIDescriptorFree(clob,ACI_DTYPE_LOB);
checkerr(err, r);
}
void write_getlength_lob
{
char *inEmpBlobSql = "insert into tabLob(id, col_blob) values(1,
empty_blob)";
char *updateBlobSql = "select col_blob from tabLob where id = 1 for
update ";
ACILobLocator *blob;
ub4 lobLen = 0;
char szBuff[LOB_BUFF_LEN] = "我是中国人, 我爱中国";
int buffLen = strlen(szBuff);
sword r = 0;
//插入空blob数据
r = ACIHandleAlloc(env,(void**)&stmt,ACI_HTYPE_STMT,0,0);
checkerr(err, r);
r = ACIStmtPrepare(stmt,err,(const OraText*)inEmpBlobSql,
(ub4)strlen(inEmpBlobSql),ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc,stmt,err,1,0,0,0,ACI_COMMIT_ON_SUCCESS);
checkerr(err, r);
r = ACIDescriptorAlloc(env,(void
**)&blob,ACI_DTYPE_LOB,0,NULL);//clob描述符初始化
checkerr(err, r);
r = ACIStmtPrepare(stmt,err,(const OraText*)updateBlobSql,
(ub4)strlen(updateBlobSql),ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIDefineByPos(stmt,&pDef[4],err,1,&blob,sizeof(blob),
SQLT_BLOB,0,0,0,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc,stmt,err,1,0,0,0,ACI_COMMIT_ON_SUCCESS);
checkerr(err, r);
r = ACILobGetLength(svc, err, blob, &lobLen);
checkerr(err, r);
printf("blob的长度为%d\n", lobLen);
r = ACILobWrite(svc,err,blob,&buffLen,1,szBuff,sizeof(szBuff),
ACI_ONE_PIECE, 0, 0, 0, SQLCS_IMPLICIT);
checkerr(err, r);
printf("实际写入的长度为%d\n", buffLen);
r = ACILobGetLength(svc,err,blob,&lobLen);
checkerr(err, r);
printf("写入后通过ACILobGetLength获取到的blob长度为%d\n", lobLen);
}
通过临时LOB写入大对象¶
创建一个临时大对象lob指针,然后往临时大对象中写入数据,将lob指针绑定到插入的列中,执行后,会将临时大对象插入到表对应的永久大对象中。
void insertblobtmp
{
// create table t_blob(a blob);
int i = 0;
ACIStmt * stmt = NULL;
ACIBind * pBind = NULL;
ACILobLocator *blob = NULL;
char buf[256];
int amtp = 256;
char * sqlstrinsert = "insert into t_blob values(:1)";
for (i = 0;i<256;i++)
{
buf[i] = i;
}
checkerr(err,ACIDescriptorAlloc(env, (dvoid **)&blob, ACI_DTYPE_LOB,
0, 0));
checkerr(err,ACILobCreateTemporary(svc,err,blob,0,0,
ACI_TEMP_BLOB,0,0));
checkerr(err,ACILobWrite(svc, err, blob, &amtp, 1, buf, sizeof(buf), 0,
0, (ACICallbackLobWrite)0, 0, 0));
checkerr(err,ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0,
0));
checkerr(err,ACIStmtPrepare(stmt, err, (OraText *)sqlstrinsert,
(ub4)strlen(sqlstrinsert), ACI_NTV_SYNTAX, ACI_DEFAULT));
checkerr(err,ACIBindByPos(stmt,&pBind,err,1,&blob,sizeof(blob),SQLT_BLOB,0,0,0,0,0,ACI_DEFAULT));
checkerr(err,ACIStmtExecute(svc, stmt, err, 1, 0, 0, 0, ACI_DEFAULT));
//必须释放临时大对象,此处省略
checkerr(err,ACITransCommit(svc, err, 0));
}
通过returning语法写入大对象¶
void insertblob
{
// create table t_blob(a blob);
int i = 0;
ACIStmt * stmt = NULL;
ACIBind * pBind = NULL;
ACILobLocator *blob = NULL;
char buf[256];
int amtp = 256;
char * sqlstrinsert = "insert into t_blob values(empty_blob)
returning a into :1";
for (i = 0;i<256;i++)
{
buf[i] = i;
}
checkerr(err,ACIDescriptorAlloc(env, (dvoid **)&blob,ACI_DTYPE_LOB,
0, 0));
checkerr(err,ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0,
0));
checkerr(err,ACIStmtPrepare(stmt, err, (OraText *)sqlstrinsert,
(ub4)strlen(sqlstrinsert), ACI_NTV_SYNTAX, ACI_DEFAULT));
checkerr(err,ACIBindByPos(stmt,&pBind,err,1,&blob,sizeof(blob),SQLT_BLOB,0,0,0,0,0,ACI_DEFAULT));
checkerr(err,ACIStmtExecute(svc, stmt, err, 1, 0, 0, 0, ACI_DEFAULT));
checkerr(err,ACILobWrite(svc, err, blob, &amtp, 1, buf, sizeof(buf), 0, 0, (ACICallbackLobWrite)0, 0, 0));
checkerr(err,ACITransCommit(svc, err, 0));
}
普通方式进行LOB写操作¶
通过LVC和LVB的方式对CLOB和BLOB进行操作,这里只列举了写入,查询也是可以通过这种普通字符串方式返回的。
//SQLT_LVC
void insertclob
{
//create table tt_clob(c clob);
int i=0;
ACIStmt * stmt = NULL;
ACIBind * pBind = {NULL};
char * sqlstrinsert = "insert into tt_clob values(:a) ";
char * par;
int width=1024*1024*100;
par = (char*)malloc(width);
memset(par,0,width);
*((int*)par)=width-4;
memset(par+4,'1',width-4);
checkerr(err,ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0,
0));
checkerr(err,ACIStmtPrepare(stmt, err, (OraText *)sqlstrinsert,
(ub4)strlen(sqlstrinsert), ACI_NTV_SYNTAX, ACI_DEFAULT));
checkerr(err,ACIBindByPos(stmt,&pBind,err,1,par,width,SQLT_LVC,0,0,0,0,0,ACI_DEFAULT));
checkerr(err,ACIStmtExecute(svc, stmt, err, 1, 0, 0, 0, ACI_DEFAULT));
checkerr(err,ACITransCommit(svc, err, 0));
free(par); par=NULL;
}
//SQLT_LVB
void insertlob
{
//create table tt_blob(b blob);
int i=0;
ACIStmt * stmt = NULL;
ACIBind * pBind =NULL;
char * par;
int width=1024*1024*100;
char * sqlstrinsert = "insert into tt_blob values(:a) ";
par = (char*)malloc(width);
memset(par,0,width);
*((int*)par)=width-4;
memset(par+4,'a',width-4);
checkerr(err,ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0,
0));
checkerr(err,ACIStmtPrepare(stmt, err, (OraText *)sqlstrinsert,
(ub4)strlen(sqlstrinsert), ACI_NTV_SYNTAX, ACI_DEFAULT));
checkerr(err,ACIBindByPos(stmt,&pBind,err,1,par,width,SQLT_LVB,0,0,0,0,0,ACI_DEFAULT));
checkerr(err,ACIStmtExecute(svc, stmt, err, 1, 0, 0, 0, ACI_DEFAULT));
checkerr(err,ACITransCommit(svc, err, 0));
free(par); par=NULL;
}
BFILE读写操作¶
其中表的结构为tabLob(id int, col_bfile bfile)。该用例需在/opt目录下存放一个1.txt的文件,内容是123456 。最终readBufp的内容是123456。
ub4 amt = 0;
int isOpen = FALSE;
int isExist = FALSE;
char readBufp[256] = {0};
int bufLen = 256;
ACIDefine *def = NULL;
ACILobLocator* bfile = NULL;
char *createT = "create table tabLob (id int, col_bfile bfile)";
char *createD = "create directory DIR as '/opt'";
char *insertT = "insert into tabLob values (1, bfilename('DIR',
'1.txt'))";
char *selectL = "select col_bfile from tabLob where id = 1";
//分配LOB定位符句柄
r = ACIDescriptorAlloc (env, (void**)&bfile, ACI_DTYPE_FILE, 0,
(dvoid**)0);
checkerr(err, r);
//Create directory
r = ACIStmtPrepare(stmt, err, (CONST OraText*)createD,
(ub4)strlen(createD), ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc, stmt, err, 1, 0, NULL, NULL, ACI_DEFAULT);
checkerr(err, r);
//Create table
r = ACIStmtPrepare(stmt, err, (CONST OraText*)createT,
(ub4)strlen(createT), ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc, stmt, err, 1, 0, NULL, NULL, ACI_DEFAULT);
checkerr(err, r);
//Insert data
r = ACIStmtPrepare(stmt, err, (CONST OraText*)insertT,
(ub4)strlen(insertT), ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc, stmt, err, 1, 0, NULL, NULL, ACI_DEFAULT);
checkerr(err, r);
r = ACITransCommit(svc, err, ACI_DEFAULT);
checkerr(err, r);
//Select locator
r = ACIStmtPrepare(stmt, err, (CONST OraText*)selectL,
(ub4)strlen(selectL), ACI_NTV_SYNTAX,ACI_DEFAULT);
checkerr(err, r);
r = ACIDefineByPos(stmt, &def, err, 1, &bfile, sizeof(ACILobLocator*),
SQLT_FILE, 0, 0, 0, ACI_DEFAULT);
checkerr(err, r);
r = ACIStmtExecute(svc, stmt, err, 1, 0, NULL, NULL, ACI_DEFAULT);
checkerr(err, r);
//check file exist
r = ACILobFileExists(svc, err, bfile, &isExist);
checkerr(err, r);
//open bfile locator
r = ACILobFileOpen(svc, err, bfile, ACI_FILE_READ_ONLY);
checkerr(err, r);
//check current bfile open or not
r = ACILobFileIsOpen(svc, err, bfile, &isOpen);
checkerr(err, r);
//读取文件数据
r = ACILobRead(svc, err, bfile, &amt, 1, readBufp, bufLen,
ACI_ONE_PIECE, 0, 0, SQLCS_IMPLICIT);
checkerr(err, r);
//关闭bfile
r = ACILobFileClose(svc, err, bfile);
checkerr(err, r);
//释放bfile
r = ACIDescriptorFree(bfile, ACI_DTYPE_FILE);
checkerr(err, r);