资源描述
OCI简介
1.OCI概述
OCI(Oracle Call Interfce,即Oracle调用层接口)是Oracle公司提供的由头文件和库函数等组成的一个访问Oracle数据库的应用程序编程接口(application programming interface API),它允许开发人员在第三代编程语言(包括C,C++,COBOL与FORTRAN)中通过SQL(Structure Query Language)来操纵Oracle数据库,而且OCI在一定程度上支持第三代编程语言(诸如C,C++,COBOL与FORTRAN)的数据类型、语法等等。OCI的显著特点是全面支持Oracle的面向对象技术,同时OCI还具有如下的一些特点:
1)非常有利于应用程序的设计;
2)高度控制应用程序的执行;
3)允许开发人员应用已熟悉的第三代程序设计语言来应用OCI;
4)支持动态SQL;
5)几乎所有的Oracle的开发工具都支持OCI;
6)通过回调技术(callbacks)来实现动态绑定与定义;
7)通过OCI的描述函数可以获取Oracle数据库的各种参数;
8)增强了数组在DML(data manipulation language)语言中的应用;
OCI接口支持Windows NT和Windows 95/98/2O0o/xP操作系统,它所支持的C语言编译器包括Borland C++和MicrosoftVisualC++等。在使用OCI开发Oralce数据库应用程序之前,应首先安装这些操作系统和C语言编译工具。在选择安
装OCI开发工具包后,Oracle安装程序将OCI文件拷贝到oracle主目录内的以下子目录中:
. . BIN\:执行文件和帮助文件:
. . \OCIINCLUDE头文件;
. . OCI\LIB\其中包含仍bc和\msvc两个子目录,分别用于存储支持Borland C++和MicroSoflVisualC++的OCI库文件,这些库文件与OCI源程序编译后所产生的目标文件进行链接生成可执行程序。一个应用OCI程序的生成可执行应用程序的过程如图1:
图
由此,我们可以看出:一个应用OCI的应用程序与其它不连接数据库的应用程序生成可执行程序的过程没有区别,在程序的链接阶段OCI库与源程序的目标代码文件链接而生成可执行程序。
2.OCI程序的基本结构
在一个应用程序中,我们是通过调用OCI提供的库函数来实现对Oracle数据库的操纵。OCI提供了上百个函数,都是以OCI开头的函数,比如创建OCI环境的OCI函数:OCIEnvCreate()。OCI函数的一个特点或者说是难点就是它的参数特别多,
函数往往都有十几个参数。
一般情况下,一个OCI应用程序都是在多用户环境下的。在一个n层网络结构的配置中,客户端的应用程序需要完成一些数据操纵,包括交换数据与处理数据。一个OCI应用程序的基本结构包括:
1)初始化OCI环境和线程;
2)分配必要的句柄与数据结构;
3)建立与数据库的连接以及创建用户会话;
4)通过SQL与Oracle服务器交换数据,而后再做数据处理:
5)结束用户会话与断开与数据库的连接;
6)释放在程序中所分配的句柄。
示意如图2。
3.在OCI应用程序中执行SQL的步骤
结构化查询语言(SQL Structure Query Language)是操纵关系数据库的主流语言,目前,几乎所有的商业数据库软件都支持SQL语言。标准的SQL语言按照它的功能不同,可以分为查询、操纵、定义以及控制四种类型。每一种都有若干关键字,具体如表1所示。
一个SQL语句在OCI应用程序中的执行步骤一般如下:
1) 准备SQL语句。调用函数OCIStmtPrepare();
2)在SQL语句中绑定需要输入到SQL语句中的变量。对于DML语句来说,由于它带有输入变量,我们可以通过调用一个或者多个函数OCIBindByPos()、OCIBindByName()等把输入变量的地址绑定在DML语句中的占位符中;
3)执行SQL语句。调用OCIStmtExecute()函数。对于DDL语句到这一步就完成了一个语句的执行;
4)描述SQL中的输出的数据。如果有必要的话,我们可以调用函数OCIParamGet()与OCIAttrGet()来获取我们所读取的记录的字段个数、字段的数据类型以及字段数据定义的最大长度。
5)定义输出变量。对于DQL(Data Query Language)语句,即SELECT的查询语句,需要定义一定数量的变量用来接受所选择列的数据。我们可以调用OCIDeflneByPos()、OCIDefineObject()函数等来完成这个任务。也就建立SQL语句所返回的数据与应用程序中变量的关系。
6)获取数据。我们可以调用函数OCIStmtFetch()来把用SELECT选中的记录的数据赋予应用程序中的变量。过程以及过程中调用到的函数如图3所示:
虽然Oracle对标准的SQL语言有所扩展,但它也是建立在标准的SQL语言的基础之上。上图是一个一般SQL执行的流程图,对于不同的SQL语句,所需要的步骤也有所不同。对于DCL与DDL语句,由于没有数据的输入与输出,仅仅涉及到一些权
限与定义或者删除数据库中的对象的问题,因此只需要上图的第一步与第三步便可以了。而对于DQL与DML语句,由于有数据的输入与输出,因此需要的步骤就多一些。其实,DML也可以只用两步来完成。这是因为DML语句中仅仅涉及数据的输入(即,数据从应用程序到数据库端),因此我们可以把所要输入的数据以字符串的形式放在SQL语句中。而DQL不仅可能有数据输入,而且也有数据输出(从数据库端到应用程序),因此,一个DQL语句需要如上图的六个步骤。
OCI环境配置
Oracle oci工具包安装:
$ORACLE_HOME\BIN:执行文件和help文件
$ORACLE_HOME\OCI\INCLUDE:头文件
$ORACLE_HOME\OCI\LIB\BC: for Borlanf C++的OCI库
$ORACLE_HOME\OCI\LIB\MSVC: for MS Visual C++的OCI库
如果是unix下,对于ORACLE8i,则OCI库在$ORACLE_HOME/lib下,如果是9i,则在$ORACLE_HOME/lib32下,库文件名一般为libclntsh.so
以上所有过程,只需安装一个oracle客户端,oci的所有头文件和库文件全部包含在内,VC开发时只需包含指定的头文件,引用相关库即可。
OCI实现操作oracle数据库
1.创建OCI环境
即创建和初始化OCI工作环境,其他的OCI函数需要OCI环境才能执行。
2.需要申请的句柄类型
OCI环境句柄: OCI_HTYPE_ENV—它定义所有OCI函数的环境调用环境,是其他句柄的父句柄。(由OCIEnvInit或OCIEnvCreate生成)
错误句柄:OCI_HTYPE_ERROR—作为一些OCI函数的参数,用来记录这些OCI函数操作过程中所产生的错误,当有错误发生时,可用COIErrorGet()来读取错误句柄 中记录的错误信息。
服务器环境句柄:OCI_HTYPE_SVCCTX—定义OCI调用的服务器操作环境,它包含服务器、用户会话和事务三种句柄。
服务器句柄:OCI_HTYPE_SERVER—标识数据源,它转换为与服务器的物理连接。
用户会话句柄:OCI_HTYPE_SESSION—定义用户角色和权限及OCI调用的执行环境。
事务句柄:OCI_HTYPE_TRANS—定义执行SQL操作的事务环境,事务环境中包含用户的会话状态信息。
语句句柄:OCI_HTYPE_STMT—是一个标识SQL语句或PL/SQL块,以及其相关属性的环境。
Bind/Define句柄:属于语句句柄的子句柄,由OCI库隐式自动生成。用户不需要自己再申请,OCI输入变量存储在bind 句柄中,输出变量存储在定义句柄中
3.句柄属性包括
服务器环境句柄属性:(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_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—返回语句选择列表中的列数
4.关于输出变量定义
如果在语句执行前就知道select语句的选择列表结构,则定义输出操作可在调用 OCISTMTExecute前进行,如果查询语句的参数为用户动态输入的,则必须在执行后定义。
5.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函数调用正在执行中。
6.OCI连接有二种方式
Blocking(阻塞方式)和non_Blocking(非阻塞方式),阻塞方式就是当调用 OCI操作时,必须等到此OCI操作完成后服务器才返回客户端相应的信息,不管是成功还是失败。非阻塞方式是当客户端提交OCI操作给服务器后,服务器立即返回OCI_STILL_EXECUTING信息,而并不等待服务端的操作完成。
对于non-blocking方式,应用程序若收到一个OCI函数的返回值为 OCI_STILL_EXECUTING时必须再次对每一个OCI函数的返回值进行判断,判断其成功与否。
可通过设置服务器属性为OCI_ATTR_NONBLOCKING_MODE来实现。系统默认方式为阻塞模式.
7.OCI函数设置的模式
OCI_DEFUALT:使用OCI默认的环境
OCI_THREADED:线程环境下使用OCI
OCI_OBJECT:对象模式
OCI_SHARED:共享模式
OCI_EVENTS
OCI_NO_UCB
OCI_ENV_NO_MUTEX:非互斥访问模式
其中模式可以用逻辑运算符进行迭加,将函数设置成多多种模式:如mode=OCI_SHREADED| OCI_OBJECT
8.事务
当应用进程与服务器断开连接时,程序没有使用OCITransCommit()进行事务的提交,则所有活动的事务会自动回滚。
9.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;
10.属性操作
在SQL语句准备后,可以用OCIAttrSet(0设置该语句的类型属性OCI_ATTR_STMT_TYPE,以后可读取语句属性,根据属性分别进行处理。
11.批量绑定输入和定义输出参数
将数据存入一个静态数据组中。一次执行可以提交或读取多行记录值。
12.占位符和指示器变量
占位符:在程序中,一些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:所读取的列数据长度大于程序变量的长度,则被截取,指示符变量值为所读取数据被截取前的实际长度
OCI函数说明
示例以下面结构作为说明
sword swResult;
OCIBind* hBind;
OCIDefine* hDefine;
OCIStmt *stmtp
OCIError *errhp;
OCIStmt *stmtp
OCISvcCtx * svchp
OCIEnv * envhpp;
OCISession * usrhp;
sb2 sb2aInd[30]; //指示器变量,用于取可能存在空值的字段
Typedef strcut
{
char tname[40];
int age;
} t_std;
typedef struct
{
sb2 sb2_tname[100];
sb2 sb2_age[100];
} stdInd_T; //指示器数组
typedef struct
{
ub2 ub2_tname[100];
ub2 ub2_age[100];
} stdLen_T; //字段长度
t_std tstd[100]; //数组变量,用于批量操作
stdInd_T tstdInd;
stdLen_T tstdLen;
stdLen_T tstdRet;
t_std std;
各函数数明
1.创建OCI环境
sword OCIEnvCreate(
OCIEnv **envhpp, //OCI环境句柄指针
ub4 mode, //初始化模式:OCI_DEFAULT/OCI_THREADED 等
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 :
swResult = OCIEnvCreate(&envhpp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCIInitialize (
ub4 mode,
CONST dvoid *ctxp,
CONST dvoid *(*malocfp) (/* dvoid *ctxp, size_t size _*/),
CONST dvoid *(*ralocfp) (/*_ dvoid *ctxp, dvoid *memptr, size_t newsize _*/),
CONST void (*mfreefp) (/*_ dvoid *ctxp, dvoid *memptr _*/)
);
sword OCIEnvInit (
OCIEnv **envhpp,
ub4 mode,
size_t xtramemsz,
dvoid **usrmempp
);
注:
在8i以后,可用OCIEnvCreate一个函数就可以初始化环境了,相当于OCIInitialize+ OCIEnvInit
2.申请/释放句柄
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
事务句柄OCISession, 句柄类型OCI_HTYPE_SESSION
上下文句柄OCISvcCtx, 句柄类型OCI_HTYPE_SVCCTX
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)
3.读取/设置句柄属性
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 //错误句柄
)
4.连接/断开服务器
多用户方式连接:
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 OCILogon (
OCIEnv *envhp,
OCIError *errhp,
OCISvcCtx **svchp,
CONST text *username,
ub4 uname_len,
CONST text *password,
ub4 passwd_len,
CONST text *dbname,
ub4 dbname_len
);
sword OCILogoff (
OCISvcCtx *svchp
OCIError *errhp
);
5.开始/结束一个会话
先认证用户再建立一个会话连接
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权限
Eg:
swResult = OCISessionBegin(svchp, errh,usrhp, OCI_CRED_RDBMS, OCI_DEFAULT);
if(swResult != OCI_SUCCESS && swResult != OCI_SUCCESS_WITH_INFO)
return FALSE;
sword OCISessionEnd (
OCISvcCtx *svchp,
OCIError *errhp,
OCISession *usrhp,
ub4 mode );
6.读取错误信息
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);
7.准备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;
8. 绑定输入参数
OCIBindArrayOfStruct() Set skip parameters for static array bind ,数组绑定,一般用于批量操作
OCIBindByName() Bind by name 按名绑定
OCIBindByPos() Bind by position 按位置绑定,建议一般按此方式绑定
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中定义每个参数所跳过的字节数。
如:
存储方式:
第一条记录第二条记录 N
SkipPara(实际就是结构体长度,即本次所有列的长度和)
sword OCIBindByPos ( OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
ub4 position, // 绑定的位置
dvoid *valuep, //缓冲区地址
sb4 value_sz, //一条记录的长度
ub2 dty, //在OCI中的数据类型
dvoid *indp, //是否为空的标志
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode );
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
展开阅读全文