转自:http://kulong0105.blog.163.com/blog/static/174406191201162145944574/
最近公司做的一个项目,要处理海量数据,数据是存放在Oracle数据库里,刚开始用的是ADO访问,速度极慢,后来改用Proc,效果还是不如人意,最后才用的OCI。因为之前对OCI不了解过,经2个星期的努力,终于完成了对Oracle数据库中的海量数据的读取与插入,速度的确很快,测试读取七千五百万条数据连一分钟都不到。
之前用Proc,没用OCI,是因为Proc容易学,OCI相对难学些,说起难学,主要就是因为Oracle提供的一百多个API函数中每个函数都至少带有七八个参数,而每个参数都具有不同的重要的意义,一不小心设置错了,可能会导致潜在的错误,调试的时候也很难发现,这个我深有体会啊!
下面结合我的学习过程,讲一下OCI编程:
1:环境的配置
一:系统环境:要想使用OCI编程需要安装Oracle的客户端,而这个普通的客户端比较大,在Oracle10g版本后推出了大小只有30M的Instantclient(即时客户端)作为Oracle的访问客户端。
具体的配置可以参考这里:http://www.cnblogs.com/ychellboy/archive/2010/04/16/1713884.html
二:执行环境:
windows下的配置可以参考这里:http://blog.csdn.net/sherlockhua/article/details/4353531
linux下的配置可以参考这里:http://blog.csdn.net/sherlockhua/article/details/4353531
2:基本理论
㈠首先要创建OCI 环境即创建和初始化OCI 工作环境,其他的OCI 函数需要OCI 环境才能执行。
㈡分配OCI 环境句柄:它定义所有OCI 函数的调用环境,是其他句柄的父句柄。( 由OCIEnvInit 或OCIEnvCreate 生成 ) 。
㈢错误句柄:作为一些OCI 函数的参数,用来记录这些OCI 函数操作过程中所产生的错误,当有错误发生时,可用OCIErrorGet() 来读取错误句柄中记录的错误信息。
㈣服务器环境句柄:定义OCI 调用的服务器操作环境,它包含服务器、用户会话和事务三种句柄。
㈤服务器句柄:标识数据源,它转换为与服务器的物理连接。
㈥用户会话句柄:定义用户角色和权限及OCI 调用的执行环境。
㈦事务句柄:定义执行 SQL 操作的事务环境,事务环境中包含用户的会话状态信息。
㈧语句句柄:是一个标识 SQL 语句或 PL/SQL 块,以及其相关属性的环境。
㈨Bind/Define句柄:属于语句句柄的子句柄,由OCI库隐式自动生成。用户不需要自己再申请,OCI输入变量存储在bind 句柄中,输出变量存储在定义句柄中。
注意:Bind/Define 句柄在执行具体的 SQL 语句的时候,被隐含创建并连接到表达句柄( Statement Handle )上,当表达句柄释放时,它们也被隐含释放。所以在执行每一个 sql 语句时,先分配表达句柄,执行结束后,释放表达句柄,这样做保证不发生由于定位句柄和绑定变量句柄引起的内存泄漏。
3:连接Oracle数据库的步骤
OCI 连接过程比较复杂,除了分配设置各个基本句柄外,还要明确彼此之间的联系,大致流程如下:
创建环境句柄: OCIEnvCreate(&envhp, …);
创建一个指定环境的错误句柄: OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp,…);
创建一个指定环境的服务器句柄: OCIHandleAlloc((dvoid *)envhp, (dvoid **)&servhp,…);
建立到数据源的访问路径 : OCIServerAttach(servhpp, errhpp,…);
创建一个指定环境的服务上下文句柄: (void) OCIHandleAlloc((dvoid *)envhpp,…);
为指定的句柄及描述符设置特定的属性: (void) OCIAttrSet((dvoid *)svchpp,…);
创建一个指定环境的用户连接句柄: (void) OCIHandleAlloc((dvoid *)envhpp,…);
为用户连接句柄设置登录名及密码: (void) OCIAttrSet((dvoid *)usrhpp,…);
认证用户建立一个会话连接: OCISessionBegin(svchpp, errhpp,…);
创建一个句子句柄: OCIHandleAlloc((dvoid *)envhpp,…);s
准备 SQL 语句: OCIStmtPrepare(stmthpp, errhpp,…);
绑定输入变量: OCIBindByPos(stmtp &hBind, errhp,…);
绑定输出变量: OCIDefineByPos(stmthpp, &bhp1, errhpp,…);
获得 SQL 语句类型: OCIAttrGet ((dvoid *)stmthpp, (ub4)OCI_HTYPE_STMT,…);
执行 SQL 语句: OCIStmtExecute(svchpp, stmthpp,…);
释放一个会话: OCISessionEnd();
删除到数据源的访问 : OCIServerDetach(servhpp, errhpp, OCI_DEFAULT);
释放句柄: OCIHandleFree((dvoid *) stmthpp, OCI_HTYPE_STMT);
4:常用句柄属性
服务器环境句柄属性: (OCI_HTYPE_SVCCTX)
OCI_ATTR_SERVER— 设置 / 读取服务环境的服务器环境属性
OCI_ATTR_SESSION— 设置 / 读取服务环境的会话认证环境属性
OCI_ATTR_TRANS— 设置 / 读取服务环境的事务环境属性
用户会话句柄属性: (OCI_HTYPE_SESSION)
OCI_ATTR_USERNAME— 设置会话认证所使用的用户名
OCI_ATTR_PASSWORD— 设置会话认证所使用的用户口令
服务器句柄: (OCI_HTYPE_SEVER)
OCI_ATTR_NOBLOCKING_MODE— 设置 / 读取服务器连接: =TRUE 时服务器连接设置为非阻塞方式
语句句柄: (OCI_HTYPE_STMT)
OCI_ATTR_ROWS_RETCHED 取得获取数据记录数
OCI_ATTR_ROW_COUNT— 只读,为当前已处理的行数,其 default=1
OCI_ATTR_STMT_TYPE— 读取当前 SQL 语句的类型:
Eg : OCI_STMT_BEGIN
OCI_STMT_SELECT OCI_STMT_INSERT
OCI_STMT_UPDATE OCI_STMT_DELETE
OCI_ATTR_PARAM_COUNT—返回语句选择列表中的列数
5:介绍一下OCI的常用函数,这些常用函数基本可以帮助你完成大多数的操作
一:创建OCI环境
sword OCIEnvCreate(
OCIEnv **envhpp, //OCI环境句柄指针
ub4 mode, //初始化模式:OCI_DEFAULT | OCI_THREADED | OCI_OBJECT等
CONST dvoid *ctxp,
CONST dvoid *(*malicfp)(dvoid *ctxp,size_t size),
CONST dvoid *(ralocfp)(dvoid *ctxp,dvoid *memptr,size_t newsize),
CONST void *(*mfreefp)(dvoid *ctxp,dvoid *memptr),
Size_t xstramemsz,
Dvoid **usrmempp
)
eg:创建OCI环境
int nresult=OCIEnvCreate(&envhpp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
二:申请/释放句柄
sword OCIHandleAlloc(
CONST dvoid *parenth, //新申请句柄的父句柄,一般为OCI环境句柄
Dvoid **hndlpp, //申请的新句柄
Ub4 type, type, //句柄类型
Size_t xtramem_sz, //申请的内存数
Dvoid **usrmempp //申请到的内存块指针
)
注: 一般需要申请的句柄有:
服务器句柄OCIServer, 句柄类型OCI_HTYPE_SERVER
错误句柄OCIError,用于捕获OCI错误信息, 句柄类型OCI_HTYPE_ERROR
上下文句柄OCISvcCtx, 句柄类型OCI_HTYPE_SVCCTX
事务句柄OCISession, 句柄类型OCI_HTYPE_SESSION
SQL语句句柄OCIStmt, 句柄类型OCI_HTYPE_STMT
eg: 申请一个错误句柄OCIError
swResult = OCIHandleAlloc(envhpp, (dvoid *)& errhp, OCI_HTYPE_ERROR, 0, NULL);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
{ return FALSE; }
释放句柄
sword OCIHandleFree(
dvoid *hndlp, //要释放的句柄
ub4 type //句柄类型
)
eg: 释放语句句柄
OCIHandleFree(stmtp, OCI_HTYPE_STMT)
三:读取/设置句柄属性
sword OCIAttrSet(
dvoid *trgthndlp, //需设置的句柄名
ub4 trghndltyp, //句柄类型
dvoid *attributep, //设置的属性名
ub4 size, //属性值长度
ub4 attrtype, //属性类型
OCIError *errhp //错误句柄
)
注:一般要设置的属性有:
服务器实例:
句柄类型OCI_HTYPE_SVCCTX,属性类型 OCI_ATTR_SERVER
连接数据库的用户名:
句柄类型OCI_HTYPE_SESSION,属性类型 OCI_ATTR_USERNAME
连接数据库用户密码:
句柄类型OCI_HTYPE_SESSION,属性类型 OCI_ATTR_PASSWORD
事务:
句柄类型OCI_HTYPE_SVCCTX,属性类型 OCI_ATTR_SESSION
eg:设置用户名和密码
char username[20],passwd[20];
strcpy(username,”tiger”)
strcpy(passwd,”cotton”)
swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*) username, strlen(username),
OCI_ATTR_USERNAME, errhp);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
swResult = OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*) passwd, strlen(passwd),
OCI_ATTR_PASSWORD, errhp);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCIAttrGet(
dvoid *trgthndlp, // 需读取的句柄名
ub4 trghndltyp, //句柄类型
dvoid *attributep, //读取的属性名
ub4 *sizep, //属性值长度
ub4 attrtype, //属性类型
OCIError *errhp //错误句柄
)
四:连接/断开服务器
多用户方式连接:
sword OCIServerAttach(
OCIServer *srvhp,// 未初始化的服务器句柄
OCIError *errhp,
CONST text *dblink,//服务器SID
sb4 dblink_len,
ub4 mode //=OCI_DEFAULT, 系统环境将设为阻塞方式
);
多用户方式断开:
sword OCIServerDetach (
OCIServer *srvhp,
OCIError *errhp,
ub4 mode //OCI_DEFAULT
);
五:开始/结束一个会话
sword OCISessionBegin (
OCISvcCtx *svchp, //服务 环境句柄
OCIError *errhp,
OCISession *usrhp, //用户会话句柄
ub4 credt, //认证类型
ub4 mode //操作模式
);
认证类型:
OCI_CRED_RDBMS: 用数据库用户名和密码进行认证,则先要设置OCI_ATTR_USERNAME和OCI_ATTR_PASSWORD属性
OCI_CRED_EXT: 外部认证,不需要设置用户和密码
OCI_DEFAULT:用户会话环境只能被指定的服务器环境句柄所设置
OCI_SYSDBA:用户 要具有sysdba权限
OCI_SYSOPER:用户要具有sysoper权限
sword OCISessionEnd (
OCISvcCtx *svchp,
OCIError *errhp,
OCISession *usrhp,
ub4 mode );
六:读取错误信息
sword OCIErrorGet (
dvoid *hndlp, // 错误句柄
ub4 recordno,//从那里读取错误记录,从1开始
text *sqlstate,//已取消,=NULL
sb4 *errcodep, //错误号
text *bufp, //错误内容
ub4 bufsiz, //bufp长度
ub4 type //传递的错误句柄类型 //=OCI_HTYPE_ERROR错误句柄 //=OCI_HTYPE_ENV: 环境句柄
);
eg:
ub4 ub4RecordNo = 1;
OCIError* hError
sb4 sb4ErrorCode;
char sErrorMsg[1024];
if (OCIErrorGet(hError, ub4RecordNo++, NULL, &sb4ErrorCode, (OraText*) sErrorMsg, sizeof(sErrorMsg), OCI_HTYPE_ERROR) == OCI_SUCCESS)
printf(“error msg:%s\n”, sErrorMsg);
七:准备SQL语句
sword OCIStmtPrepare (
OCIStmt *stmtp,//语句句柄
OCIError *errhp,
CONST text *stmt, //SQL语句
ub4 stmt_len, //语句长度
ub4 language, //语句的语法格式=OCI_NTV_SYNTAX
ub4 mode //=OCI_DEFAULT
);
eg:
char sSQL[1024];
sprintf(sSQL, “select table_name from user_tables”);
swResult = OCIStmtPrepare(stmtp errhp, (CONST OraText*)sSQL, strlen(sSQL), OCI_NTV_SYNTAX, OCI_DEFAULT);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
八:绑定输入参数
OCIBindByName()----------------------按名绑定
OCIBindByPos()------------------------按位置绑定,建议一般按此方式绑定
OCIBindArrayOfStruct() -------------数组绑定,一般用于批量操作
OCIBindDynamic() Sets additional attributes after bind with OCI_DATA_AT_EXEC mode
OCIBindObject() Set additional attributes for bind of named data type
注: OCIBindArrayOfStruct 必须先用OCIBindByPos初始化,然后在OCIBindArrayOfStruct中定义每个参数所跳过的字节数。
sword OCIBindByName (
OCIStmt *stmtp, // 语句句柄
OCIBind **bindpp,//结合句柄,=NULL
OCIError *errhp,
CONST text *placeholder,//占位符名称
sb4 placeh_len, // 占位符长度
dvoid *valuep, //要替换的值的地址
sb4 value_sz, // 要替换的值的最大字节数
ub2 dty, //绑定的类型
dvoid *indp, //指示符变量指针(sb2类型),单条绑定时为NULL,
ub2 *alenp, // 说明执行前后被结合的数组变量中各元素数据实际的长度,单条绑定时为NULL
ub2 *rcodep,// 列级返回码数据指针,单条绑定时为NULL
ub4 maxarr_len, //最多 的记录数,如果是单条绑定,则为0
ub4 *curelep, //实际的记录数,单 条绑定则为NULL
ub4 mode //=OCI_DEFAULT
);
sword OCIBindByPos (
OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
ub4 position,// 绑 定的位置
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode );
sword OCIBindArrayOfStruct (
OCIBind *bindp,//绑定的结构句柄,由OCIBindByPos定义
OCIError *errhp,
ub4 pvskip, //下一列跳过的字节数
ub4 indskip,// 下一个指示器或数组跳过的字节数
ub4 alskip, //下一个实际值跳过的字节数
ub4 rcskip //下一个列级返回值跳过的字节数
);
九:定义输出变量
OCIDefineArrayOfStruct() Set additional attributes for static array define
OCIDefineByPos() Define an output variable association
OCIDefineDynamic() Sets additional attributes for define in OCI_DYNAMIC_FETCH mode
OCIDefineObject() Set additional attributes for define of named data type
sword OCIDefineByPos (
OCIStmt *stmtp, //语句句柄
OCIDefine **defnpp,// 定义句柄—用于数组变量
OCIError *errhp,
ub4 position,// 位置序号(从1 开始)
dvoid *valuep, //输出的变量名
sb4 value_sz, // 变量长度
ub2 dty, //数据类型
dvoid *indp, // 指示器变量/指示器变量数组,如果此字段可能存在空值,则要指示器变量,否则单条处理时为NULL
ub2 *rlenp, // 提取的数据长度
ub2 *rcodep, //列级返回码数组指针
ub4 mode //OCI_DEFAULT
);
sword OCIDefineArrayOfStruct (
OCIDefine *defnp,// 由OCIDefineByPos定义的句柄
OCIError *errhp,
ub4 pvskip, // 下一列跳过的字节数,一般就是结构的大小
ub4 indskip,//下一个指示器或结构 跳过的字节数,=0
ub4 rlskip, //下一个实际值跳过的字节数,=0
ub4 rcskip // 下一个列列级返回值跳过的字节数,=0
);
sword OCIDefineObject (
OCIDefine *defnp,
OCIError *errhp,
CONST OCIType *type,
dvoid **pgvpp,
ub4 *pvszsp,
dvoid **indpp,
ub4 *indszp
);
eg:
单条查询
sql: select username,age from student where username=:p1;
如果此字段有可能有空值,则
hDefine = NULL;
swResult = OCIDefineByPos(stmtp &hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, & sb2aInd[0], NULL, NULL, OCI_DEFAULT);
如果此字段没有空值,则
hDefine = NULL;
swResult = OCIDefineByPos(stmtp &hDefine, errhp, 1, tstd.username, sizeof(tstd.username), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT);
批量查询
select username,age from student where age>;30;
hDefine = NULL;
swResult = OCIDefineByPos(stmtp, &hDefine, errhp, 1, &tstd[0].username,
sizeof(tstd[0].usenmae), SQLT_CHR, NULL, NULL, NULL, OCI_DEFAULT);
swResult = OCIDefineArrayOfStruct(hDefine, errhp, sizeof(tstd[0]), 0, 0, 0);
十:执行SQL语句
sword OCIStmtExecute (
OCISvcCtx *svchp, // 服务环境句柄
OCIStmt *stmtp, //语句句柄
OCIError *errhp,
ub4 iters, // **
ub4 rowoff, //**
CONST OCISnapshot *snap_in,
OCISnapshot *snap_out,
ub4 mode //**
);
注:
1. iters:对于select语句,它说明一次执行读取到buffer中的记录行数,如果不能确定select语句所返回的行数,可将iters设置为 0,而对于其他的语句,iters表示这些语句的执行次数,此时iters不能为0。
2. rowoff:在多行执行时,该参数表示从所结合的数据变量中的第几条记录开始执行(即记录偏移量)。
3. mode:
=OCI_DEFAULT:default模式
=OCI_DESCRIBE_ONLY:描述模式,只返回选择列表的描述信息,而不执行语句
=OCI_COMMIT_ON_SUCCESS:自动提交模式,当执行成功后,自动提交。
=OCI_EXACT_FETCH:精确提取模式。
=OCI_BATCH_ERRORS:批错误执行模式:用 于执行数组方式的操作,在此模式下,批量insert ,update,delete时,执行过程中任何一条记录错误不会导致整个 insert ,update,delete失败,系统自动会收集错误信息,而在非批错误方式下,其中的任何一条记录错误,将会导致整个操作失败。
Eg:
执行一次
swResult = OCIStmtExecute(svchp, stmtp, errhp,1, 0, NULL, NULL, OCI_DEFAULT);
批量执行100次:
swResult = OCIStmtExecute(svchp, stmtp, errhp, 100, 0, NULL, NULL, OCI_DEFAULT);
十一:提取结果
sword OCIStmtFetch (
OCIStmt *stmtp,//语句句柄
OCIError *errhp,
ub4 nrows, //从当前位置处开始一次提取的记录数,对于数据变量,可 以>;1,否则不能>;1
ub2 orientation,//提取 的方向:OCI_FETCH_NEXT
ub4 mode //OCI_DEFAULT
)
eg:
while ((swResult=OCIStmtFetch stmtp errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT)) != OCI_NO_DATA)
{
……
}
十二:事务操作
开始一个事务
sword OCITransStart (
OCISvcCtx *svchp,
OCIError *errhp,
uword timeout, //**
ub4 flags );
注:
1. Timeout:
当flag=OCI_TRANS_RESUME:它表示还有多少秒事务将被激活 ,=OCI_TRANS_NEW: 事务响应的超时时间(秒)
2. Flags:指定一个新的事务还是已有事务
=OCI_TRANS_NEW:定义一个新的事务
=OCI_TRANS_RESUME
准备一个事务:
sword OCITransPrepare (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT
sword OCITransForget (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT
断开一个事务:
sword OCITransDetach (
OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );//OCI_DEFAULT
提交一个事务:
sword OCITransCommit (
OCISvcCtx *svchp, //服务环境句柄
OCIError *errhp,
ub4 flags ); //OCI_DEFAULT
回滚一个事务
sword OCITransRollback (
dvoid *svchp,
OCIError *errhp,
ub4 flags ); //OCI_DEFAULT
关于OCI编程的各个函数的参数详细解释可以参考Oracle官网的在线手册,非常好用。
参考地址:http://download.oracle.com/docs/cd/A91202_01/901_doc/appdev.901/a89857/toc.htm
6:介绍一下OCI需要注意的地方
一: 关于输出变量定义:如果在语句执行前就知道select语句的选择列表结构,则定义输出操作可在调用 OCISTMTExecute前进行,如果查询语句的参数为用户动态输入的,则必须在执行后定义。
二:OCI函数返回值:
OCI_SUCCESS –函数执行成功 (=0)
OCI_SUCCESS_WITH_INFO – 执行成功,但有诊断消息返回,可能是警告信息
OCI_NO_DATA—函数执行完成,但没有其他数据
OCI_ERROR—函数执行错 误
OCI_INVALID_HANDLE—传递给函数的参数为无效句柄,或传回的句柄无效
OCI_NEED_DATA—需要应用程序 提供运行时刻的数据
OCI_CONTINUE—回调函数返回代码,说明回调函数需要OCI库恢复其正常的处理操作
OCI_STILL_EXECUTING —服务环境建立在非阻塞模式,OCI函数调用正在执行中。
三: OCI连接有二种方式:Blocking(阻塞方式)和non_Blocking(非阻塞方式),阻塞方式就是当调用 OCI操作时,必须等到此OCI操 作完成后服务器才返回客户端相应的信息,不管是成功还是失败。非阻塞方式是当客户端提交OCI操作给服务器后,服务器立即返回 OCI_STILL_EXECUTING信息,而并不等待服务端的操作完成。 对于non- blocking方式,应用程序若收到一个OCI函数的返回值为 OCI_STILL_EXECUTING时必须再次对每一个OCI函数的返回值进行判 断,判断其成功与否。 可通过设置服务器属性为OCI_ATTR_NONBLOCKING_MODE来实现。系统默认方式为阻塞模式。
四: OCI函数设置的模式有:
OCI_DEFUALT:使用OCI默认的环境
OCI_THREADED:线程环境下使用OCI
OCI_OBJECT:对象模式 //大家注意这个,当使用Orcale Spatial空间数据库时需要加上次模式。
OCI_SHARED:共享模式
OCI_EVENTS
OCI_NO_UCB
OCI_ENV_NO_MUTEX:非互斥访问模式
其中模式可以用逻辑运算符进行迭加,将函数设置成多多种模式:如 mode=OCI_SHREADED| OCI_OBJECT
五: 当应用进程与服务器断开连接时,程序没有使用OCITransCommit()进行事务的提交,则所有活动的事务会自动回滚。
六: OCI重定义数据类型
typedef unsigned char ub1;
typedef signed char sb1;
typedef unsigned short ub2;
typedef signed short sb2;
typedef unsigned int ub4;
typedef signed int sb4;
typedef ub4 duword;
typedef sb4 dsword;
typedef dsword dword;
七: 在SQL语句准备后,可以用OCIAttrSet(设置该语句的类型属性OCI_ATTR_STMT_TYPE,以后可读取语句属性,根据属性分别进行处理。
八: 批量绑定输入和定义输出参数:将数据存入一个静态数据组中。一次执行可以提交或读取多行记录值。
九:结合占位符和指示器变量:
①占位符:在程序中,一些SQL语句需要在程序运行时才能确定它的语句数据,在设计时可用一个占位符来代替,当程序运行 时,在它准备好语句后,必须为每个占位符指定一个变量,即将占位符与程序变量地址结合,执行时,Oracle就从这些变量中读取数据,并将它们与SQL语 句一起传递给Oracle服务器执行。OCI结合占位符时,它将占位符与程序变量关联起来,并同时要指出程序变量的数据类型和数据长度。
如:select * from test where name=:p1 and age=:p2 (:p1和:p2为占位符 )
②指示器变量:由于在Oracle中,列值可以为NULL,但在C语言中没有NULL 值,为了能使OCI程序表达NULL列值,OCI函数允许程序为所执行语句中的结合变量同时关联一个指示符变量或指示符变量数组,以说明所结合的占位符是 否为NULL或所读取的列值是否为NULL,以及所读取的列值是否被截取。
除SQLT_NTY(SQL Named DataType)外,指示符变量或指示符变量数组的数据类型为sb2,其值说明:
作为输入变量时:(如insert ,update语句中)
=-1:OCI程序将NULL赋给Oracle表的列,忽略占位符结合的程序变量值
>;=0:应用程序将程序变量值赋给指定列
作 为输出变量时:(如select语句中)
=-2:所读取的列数据长度大于程序变量的长度,则被截取。
=-1:所读取的值为 NULL,输出变量的值不会被改变。
=0:数据被完整读入到指定的程序变量中
>0:所读取的列数据长度大于程序变量的长度,则被截 取,指示符变量值为所读取数据被截取前的实际长度
终于写完了,基本上就这么多了,希望对你有帮助。
这里不能添加附加,直接贴代码的话,不是我的风格。下面给大家介绍可以学习和直接拿来用的代码地址:
①一个简单的连接Oracle数据库的代码,详细的说明了连接Oracle数据库的步骤(比较简单,没有输入与输出)
参考地址:http://blog.csdn.net/sherlockhua/article/details/4353531 (适合初学者)
②我写的一个简单的OCI接口类,能批量读取和插入数据的类,里面涉及了一些比较常用函数的用法,值得看一下
参考地址:http://www.pudn.com/downloads371/sourcecode/database/detail1607043.html
③关于Oracle空间数据库的读取与写入 (比较全面,也比较复杂)
参考地址:http://www.codesky.net/article/doc/200406/20040619864916.htm