Linux下使用C/C++访问数据库——Oracle之OCI篇
一、什么是OCI?
开发基于Oracle数据库的应用程序,我们可以选择多种工具,不仅可以用一般的数据库开发技术,诸如ADO(ActiveX Data Objects)、ODBC(Open DataBase Connectivity)等等,同时,也可以用Oracle公司提供的专门的开发工具,诸如Pro C_C++,OCI(Oracle Call Intedace)等等。比较这几种方式,前者因为是通用技术,开发起来比较容易,但是有一个致命的弱点就是诸如ADO之类的通用技术的速度太慢,如果我们要开发管理海量数据的数据库,比如影像数据库,那么,这种速度我们是不能忍受的。而OCI虽然开发起来难度大一些,但是它的速度极快,而且是一种底层接口,几乎可以操纵Oracle数据库的任何对象。
二、OCI简介
OCI(Oracle Call Intedace,即0racle调用层接口)是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/2000/XP操作系统,它所支持的C语言编译器包括Borland C++和MiroSoft VisualC++等。在使用0CI开发Oralce数据库应用程序之前,应首先安装这些操作系统和C语言编译工具。在选择安装OCI开发工具包后,Oracle安装程序将0CI文件拷贝到oracle主目录内的以下子目录中:..BIN/:执行文件和帮助文件:../OCIINCLUDE头文件;
三、开发前的注意事项
首先,为了防止某些动态链接库出问题,建议在安装了Oracle客户端的机器上进行开发、运行。其次,使用OCI开发的程序,需要使用Oracle客户端的tnsnames.ora这个配置文件,所以在开发前需要使用netca来配置好相关内容。第三,Linux下的系统环境变量需要设置好。需要设置的环境变量包括ORACLE_HOME、ORACLE_SID、TNS_ADMIN,其中TNS_ADMIN指定到tnsnames.ora所在的文件夹。
四、程序开发:
还是直接用代码说话吧/*
* Common.h
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#ifndef COMMON_H_
#define COMMON_H_
#include <unistd.h>
#include <oci.h>
#include <ctype.h>
#include <string>
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
#endif /* COMMON_H_ */
/*
* Exception.h
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#ifndef EXCEPTION_H_
#define EXCEPTION_H_
class Exception
{
public:
Exception(int errno);
virtual char * GetErrMsg() = 0;
virtual char * GetErrFunc() = 0;
virtual int GetErrNo() = 0;
protected:
int m_iErrNo;
char m_sErrBuff[512];
char m_sErrFunc[128];
};
#endif /* EXCEPTION_H_ */
/*
* Exception.cpp
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#include "Exception.h"
Exception::Exception(int errno)
{
this ->m_iErrNo = errno;
this ->m_sErrBuff[0] = 0;
this ->m_sErrFunc[0] = 0;
}
/*
* OCIException.h
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#ifndef OCIEXCEPTION_H_
#define OCIEXCEPTION_H_
#include "Common.h"
#include "Exception.h"
class OCIException : public Exception
{
public:
OCIException(sb4 errno);
OCIException(sb4 errno, char * errfunc);
OCIException(sb4 errno, dvoid * erroci);
OCIException(sb4 errno, dvoid * erroci, char * errfunc);
char * GetErrMsg();
char * GetErrFunc();
int GetErrNo();
private:
void CheckError(sb4 errno);
void CheckError(sb4 errno, dvoid * erroci);
};
#endif /* OCIEXCEPTION_H_ */
/*
* OCIException.cpp
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#include "OCIException.h"
void OCIException::CheckError(sb4 errno)
{
text errBuff[512];
switch ( errno )
{
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
sprintf( this ->m_sErrBuff, "OCI_SUCCESS_WITH_INFO" );
break;
case OCI_NEED_DATA:
sprintf( this ->m_sErrBuff, "OCI_NEED_DATA" );
break;
case OCI_NO_DATA:
sprintf( this ->m_sErrBuff, "OCI_NO_DATA" );
break;
case OCI_ERROR:
sprintf( this ->m_sErrBuff, "OCI_ERROR" );
break;
case OCI_INVALID_HANDLE:
sprintf( this ->m_sErrBuff, "OCI_INVALID_HANDLE" );
break;
case OCI_STILL_EXECUTING:
sprintf( this ->m_sErrBuff, "OCI_STILL_EXCUTING" );
break;
case OCI_CONTINUE:
sprintf( this ->m_sErrBuff, "OCI_CONTINUE" );
break;
default:
break;
}
}
void OCIException::CheckError(sb4 errno, dvoid * erroci)
{
text errBuff[512];
switch ( errno )
{
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
sprintf( this ->m_sErrBuff, "OCI_SUCCESS_WITH_INFO" );
break;
case OCI_NEED_DATA:
sprintf( this ->m_sErrBuff, "OCI_NEED_DATA" );
break;
case OCI_NO_DATA:
sprintf( this ->m_sErrBuff, "OCI_NO_DATA" );
break;
case OCI_ERROR:
OCIErrorGet( (dvoid*)erroci, (ub4)1, (text*)NULL, &this ->m_iErrNo, errBuff, (ub4)sizeof(errBuff), OCI_HTYPE_ERROR);
sprintf( this ->m_sErrBuff, "%.*s", strlen((char*) errBuff) - 1, errBuff);
break;
case OCI_INVALID_HANDLE:
sprintf( this ->m_sErrBuff, "OCI_INVALID_HANDLE" );
break;
case OCI_STILL_EXECUTING:
sprintf( this ->m_sErrBuff, "OCI_STILL_EXCUTING" );
break;
case OCI_CONTINUE:
sprintf( this ->m_sErrBuff, "OCI_CONTINUE" );
break;
default:
break;
}
}
OCIException::OCIException(sb4 errno) : Exception( (int)errno )
{
this ->CheckError(errno);
}
OCIException::OCIException(sb4 errno, char * errfunc) : Exception( (int)errno )
{
strcpy( this ->m_sErrBuff, errfunc);
this ->CheckError(errno);
}
OCIException::OCIException(sb4 errno, dvoid * erroci) : Exception( (int)errno )
{
this ->CheckError(errno, erroci);
}
OCIException::OCIException(sb4 errno, dvoid * erroci, char * errfunc) : Exception( (int)errno )
{
strcpy( this ->m_sErrBuff, errfunc);
this ->CheckError(errno, erroci);
}
char * OCIException::GetErrMsg()
{
return this ->m_sErrBuff;
}
char * OCIException::GetErrFunc()
{
return this ->m_sErrFunc;
}
int OCIException::GetErrNo()
{
return this ->m_iErrNo;
}
/*
* OCIError.h
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#ifndef OCIERROR_H_
#define OCIERROR_H_
#include "Common.h"
class OCIError
{
public:
static void PrintError(int errno);
static void PrintError(int errno, char * errfunc);
private:
static void CheckError();
static int m_iErrNo;
static char m_sErrBuff[512];
static char m_sErrFunc[128];
};
#endif /* OCIERROR_H_ */
/*
* OCIError.cpp
*
* Created .: Mar 1, 2009
* Author: Steven Wee
*/
#include "OCIError.h"
int OCIError::m_iErrNo = 0;
char OCIError::m_sErrBuff[512] = {0};
char OCIError::m_sErrFunc[128] = {0};
void OCIError::CheckError()
{
switch ( OCIError::m_iErrNo )
{
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
sprintf( OCIError::m_sErrBuff, "OCI_SUCCESS_WITH_INFO" );
break;
case OCI_NEED_DATA:
sprintf( OCIError::m_sErrBuff, "OCI_NEED_DATA" );
break;
case OCI_NO_D