您的位置:首页 > 编程语言 > C语言/C++

OCI接口简介及其在VC++中的应用(中)

2017-09-05 13:16 330 查看
OCI接口简介及其在VC++中的应用(中)
public:

    OCIEnv        *envhp;//环境句柄

    OCIServer     *srvhp;//服务器句柄

    OCISvcCtx     *svchp;//服务环境句柄

    OCIError      *errhp;//错误句柄

    OCISession    *authp;//会话句柄

    OCIStmt       *stmthp;//语句句柄

    OCIDescribe   *dschp;//描述句柄

    其次,在本工程的对话框资源中加入一个Button控件(序号1,详细配置见表4,以下加入的控件的配置情况都在表4中), 同时利用ClassWizard为该按钮添加一个“BN_CLICKED”函数――OnButConnectdb(),在这个函数中我们实现OCI程序的前三步,即:创建OCI环境,分配句柄与数据结构,连接数据库与开始会话。并且列举数据库中某个用户的所有基表。

    第三,我们在对话框中加入一个List Box控件(序号2),并且利用ClassWizard为该控件添加两个变量: m_listTablename(类型为ClistBox)与m_strTablename (类型为Cstring)。我们在该控件中显示所连接用户的所有基表(table base)。

我们在OnButConnectdb()中添加创建OCI环境的代码4.1.2。

//代码4.1.2,初始化OCI环境

OCIEnvInit(&envhp,OCI_DEFAULT,0, 0 );

我们在类COCIExampleDlg中加入一个报告OCI错误的函数ErrorProc(),代码如下:

//代码4.1.3

ErrorProc(dvoid *err, sword status)

{

Cstring str;sb4 errcode;text errbuf[512];

if(status==OCI_ERROR)

{

//调用OCI的错误获取函数

OCIErrorGet((dvoid*)errhp,(ub4)1,NULL,

&errcode,errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);

str.Format("错误号:%d/n错误信息:%s/n",

errcode,errbuf);

AfxMessageBox(str);

}}

4.2分配句柄与数据结构

在函数OnButConnectdb()中加入如4.2.1代码来分配OCI的句柄与描述符。

//代码4.2.1:分配句柄与数据结构

//分配错误句柄

OCIHandleAlloc(envhp,(void**)&errhp,

OCI_HTYPE_ERROR,0,0);

//分配服务器句柄

    OCIHandleAlloc(envhp,(void**)&srvhp,

OCI_HTYPE_SERVER,0,0);

//分配服务环境句柄

    OCIHandleAlloc(envhp,(void**)&svchp,

OCI_HTYPE_SVCCTX,0,0);

//分配会话句柄

OCIHandleAlloc(envhp,(void **)&authp,

OCI_HTYPE_SESSION,0,0);

//分配描述句柄

 OCIHandleAlloc((dvoid *) envhp,

(dvoid **) &dschp, OCI_HTYPE_DESCRIBE,0,0);

//分配语句句柄

OCIHandleAlloc((dvoid *) envhp,

(dvoid**)&stmthp, OCI_HTYPE_STMT,  0, 0));

说明:常量 “OCI_HTYPE_STMT”等等是OCI句柄的宏定义,标明我们所分配的句柄的类型。句柄的宏定义具体可以参考oci.h文件中的“Handle Types”部分。

4.3连接数据库与开始会话

由于在连接数据库与开始用户会话中需要数据库实例的名称、用户名称以及用户密码,因此我们在这个工程中加入一个对话框类来接收这些信息的输入。在OCIExample工程中加入基于CDialog类的对话框类――CCconnectDlg类。

加入CcconnectDlg类的步骤:首先,在VC的“WorkSpace/ResourceView”中选中“Dialog”,并且右击鼠标后,弹出上下文菜单,选中“Insert Dialog”,这样就给本工程中加入了一个对话框资源;其次,选中刚才加入的对话框,右击鼠标,选中上下文菜单中的“ClassWizard”,选择“Create new Class”,输入类的名称――CCconnectDlg;第三,在刚加入的对话框上(CcconnectDlg)加入如表2的控件。第四,给其中的三个CEdit控件加入用来接收用户输入信息的CString类型的变量,如表1。这样就在本工程中加入了一个可以接收输入用户信息的对话框类。

N

对象

ID

Caption或变量

1

Static Text

IDC_STATIC

OracleDB

2

CEdit

IDC_DBNAME

m_strDBName

3

Static Text

IDC_STATIC

UserName

4

CEdit

IDC_UNAME

m_strUserName

5

Static Text

IDC_STATIC

UserID

6

CEdit

IDC_UID

m_strUserID

 

 
 
 
 
 
               

表2

接着我们在函数OnButConnectdb()中加入如4.3.1代码,来接收用户输入信息。

//代码4.3.1,生成接收用户输入数据的对话框

CConectDlg  ConnDlg;

ConnDlg.m_strDBName="MyOracleDB";

ConnDlg.m_strUserName="scott";

ConnDlg.m_strUserID="tiger";

if(ConnDlg.DoModal()==IDCANCEL)return;

下面我们就可以利用用户输入的登录信息来连接数据库并且开始会话。

在函数OnButConnectdb()中加入连接数据库代码。

//代码4.3.2,连接数据库

UpdateData(TRUE);sword status;

status=OCIServerAttach(srvhp,errhp,

(unsignedchar*)(LPCTSTR)ConnDlg.m_strDBName, (sb4)strlen(ConnDlg.m_strDBName),OCI_DEFAU;

// 设置数据库的属性:服务器环境

ErrorProc(errhp,OCIAttrSet((dvoid *) svchp,

                    (ub4) OCI_HTYPE_SVCCTX,

                  (dvoid *) srvhp, (ub4) 0,

                  OCI_ATTR_SERVER, errhp));

//代码4.3.3,认证用户并且开始会话

LPCTSTR uid, pwd;

uid=ConnDlg.m_strUserName;

pwd=ConnDlg.m_strUserID;

//认证用户名称;

ErrorProc(errhp,OCIAttrSet(authp,

    OCI_HTYPE_SESSION, (dvoid *)uid,

(ub4)strlen(uid),OCI_ATTR_USERNAME,errhp));

//认证用户密码

ErrorProc(errhp,OCIAttrSet(authp,

OCI_HTYPE_SESSION, (dvoid *)pwd,

(ub4)strlen(pwd),OCI_ATTR_PASSWORD,errhp));

//以申明的用户名称与密码开始会话

status=OCISessionBegin(svchp, errhp,

  authp,OCI_CRED_RDBMS,OCI_DEFAULT);                           

if(status!=0) return ;

// 设置服务器环境

status=OCIAttrSet(svchp,OCI_HTYPE_SVCCTX,

 (dvoid*)authp,0,OCI_ATTR_SESSION,errhp);

 if(status!=0) return;

 

4.4执行SQL

这一部分比较如复杂。在OCI环境中执行SQL的过程在第二部分的3中已经分析过了。我们首先做一个没有条件的SELECT类型的SQL语句中OCI中的执行过程,而且按照第二部分的3中的步骤进行。在在函数OnButConnectdb()中加入如下几段代码,其目的就是把我们所连接的数据库的某个用户的所有基表都读取到应用程序中,并且把基表的名称显示到到我们在4.1中加入的ListBox控件中。

首先,要在本过程的类COCIExampleDlg中加入一些public类型的变量与OCI的句柄。如代码4.4.1

代码4.4.1

    OCIDefine *defhp[20];//定义句柄

    OCIBind   *bidhp[20];//绑定句柄

    OCIParam *colhp;     //列句柄

    ub2 collen[30]; //列长度

    ub2 coltype[30];//列类型

//存放SELECT语句选中的列数据

    text* colbuf[30];

    sb2 ind[30];//指示符变量

我们注意到,这里有诸如ub2、text等变量类型,这是OCI的头文件oci.h中定义的一些适合OCI的C语言变量类型,其中常用类型与C语言的对应关系如表3:更详细的资料可以参考oci.h文件的宏定义部分。

OCI类型
C语言类型
OCI类型
C语言类型
Text
unsigned char
size_t
unsigned int
sword
signed int
sb4
signed int
Ub1
unsigned char
sb2
signed char
Ub 2
unsigned short
sb1
signed char
Ub 4
unsigned int
eb4
int
 

 

 

 

 

 

 

 

 

表3
//代码4.4.2,处理SQL的第一步,准备SQL

CString strSQL; text textSQL[1024];

strSQL="SELECT TABLE_NAME FROM USER_TABLES";

wsprintf((char*)textSQL,"%s",strSQL);

status=OCIStmtPrepare(stmthp,errhp,

textSQL,strlen((char*)textSQL),

OCI_NTV_SYNTAX,OCI_DEFAULT );

由于我们所要处理的这个SELECT语句没有选择条件,即SQL语句中没有输入数据。因此我们就不需要处理SQL的第二步“绑定”;

//代码4.4.3,处理SQL的第三步:执行

ErrorProc(errhp,OCIStmtExecute(svchp,

stmthp,errhp,(ub4)0,0,

NULL,NULL, OCI_DEFAULT))

 

//代码4.4.4,处理SQL的第四步,描述

ub4 col_num;//存放SELECT语句选中的列数

//为选择项分配参数描述符

ErrorProc(errhp,OCIParamGet(stmthp,

OCI_HTYPE_STMT,errhp,

(void **)&colhp,1));

//读取选择项的数据长度

ErrorProc(errhp,OCIAttrGet(colhp,

OCI_DTYPE_PARAM,&collen[0],0,

        OCI_ATTR_DATA_SIZE,errhp));

//读取选择项的数据类型

ErrorProc(errhp,OCIAttrGet(colhp,

OCI_DTYPE_PARAM,&coltype[0],0,

        OCI_ATTR_DATA_TYPE,errhp));

//分配缓冲区

colbuf[0]=(text*)new text[(int)collen[0]+1];

//代码4.4.5处理SQL的第五步,定义变量

ErrorProc(errhp,OCIDefineByPos(stmthp,

&defhp[k-1], errhp, 1,

(ub1*)colbuf[0],collen[0]+1,

SQLT_STR,&ind[0],0,0,OCI_DEFAULT));

//代码4.4.6,处理SQL的第六步,取值

while((OCIStmtFetch(stmthp,errhp,1,

OCI_FETCH_NEXT,OCI_DEFAULT))!=OCI_NO_DATA)

{

//把获取的用户的基表的名称加到ListBox中m_listTablename.AddString((char*)

colbuf[0]);

}

delete  colbuf[0]; //删除所分配的缓冲区

 

4.5结束会话、断开连接

以及释放句柄

以上我们就已经做了一个OCI应用程序六步骤的前三步,即创建OCI环境、分配句柄与数据结构、连接数据库与开始会话以及执行SQL与处理数据,那么,一个完整的OCI应用程序还需要两个步骤,即结束会话与断开连接与释放句柄,我们可以把这两部分放在COCIExampleDlg类的析构函数中,或者类COCIExampleDlg的虚函数DestroyWindow()中,代码如下:

//代码4.5.1,

//结束会话

OCISessionEnd(svchp, errhp, authp, (ub4) 0);

//断开与数据库的连接

OCIServerDetach(srvhp,errhp,OCI_DEFAULT);

//释放OCI句柄

OCIHandleFree((dvoid*)srvhp,

OCI_HTYPE_SERVER);

OCIHandleFree((dvoid*)svchp,

OCI_HTYPE_SVCCTX);

OCIHandleFree((dvoid*)errhp,

OCI_HTYPE_ERROR);

OCIHandleFree((dvoid*)authp,

OCI_HTYPE_SESSION);

OCIHandleFree((dvoid*)stmthp,

OCI_HTYPE_STMT);

OCIHandleFree((dvoid*)dschp,

OCI_HTYPE_DESCRIBE);

4.6小结

从4.1到4.4就是在一个应用程序中应用OCI的完整步骤。但是仅仅在4.3中演示了不带条件的DQL语句在OCI中的应用方法,还没有涉及到其它类型的SQL语句。因此,下面的内容是进一步演示各种类型的SQL语句在OCI中的实现过程。

5.在ListCtrl控件中显示表的数据

我们先在对话框上添加一个Button控件(序号3)与一个List Control(序号4)(具体配置见表),并且加入control类型的变量m_listCtrl。然后利用ClassWizard为Button控件添加一个“BN_CLICKED”函数――OnBTableselectok()。我们利用这个函数实现从控件2选中的表里读出字段名以及数据并且把它们显示到控件4上。同时,我们在类COCIExampleDlg中加入如下的public类型的变量:

//代码5

//存储表的字段名称

CString ColName[50]; //存储表的字段名称

CString ColType[50];//存储字段的的数据类型

CString ColVal[50][100]; //存储表的字段值

int ColumnNumbers; //字段的数目

CString TableName; //所选中表的名称

 

在函数OnBTableselectok()中添加代码如下:

//代码5.1,获取控件2所选中的表名

TableName="";

int item=m_listTablename.GetCurSel();

m_listTablename.GetText(item,TableName);

if(TableName=="") return;

 

//代码5.2,处理SQL的第一步,准备SQL

text textSQL[1024]; sword status;

wsprintf((char*)textSQL,

"SELECT * FROM %s",TableName);

if(status=OCIStmtPrepare(stmthp,errhp,

textSQL,strlen((char*)textSQL),

OCI_NTV_SYNTAX,OCI_DEFAULT ))

{ErrorProc(errhp,status); return;}

 

//代码5.3,处理SQL的第三步,执行

if(status=OCIStmtExecute(svchp,stmthp,

errhp,(ub4)0,0,NULL,NULL,OCI_DEFAULT))

{ ErrorProc(errhp,status); return; }

//代码5.4,处理SQL的第四步,描述

ub4 col_num;//存放SELECT语句选中的列数

//代码5.4.1,读取选择列表中的项数

ErrorProc(errhp,OCIAttrGet(stmthp,

OCI_HTYPE_STMT,&col_num,0,

    OCI_ATTR_PARAM_COUNT,errhp));

ColumnNumbers=(int) col_num;

text     *namep; //字段名称

ub4       sizep; //字段名称的字符串长度

text tempText[100];

//获取表的字段的属性信息

for(int i=0;i<(int)col_num;i++)

{

//为选择项分配参数描述符

ErrorProc(errhp,OCIParamGet(stmthp,

OCI_HTYPE_STMT,errhp,

(void **)&colhp,ub4(i+1)));

//读取选择项的数据长度

ErrorProc(errhp,OCIAttrGet(colhp,

OCI_DTYPE_PARAM,&collen[i],0,

        OCI_ATTR_DATA_SIZE,errhp));

//读取选择项的数据类型

ErrorProc(errhp,OCIAttrGet(colhp,

OCI_DTYPE_PARAM,&coltype[i],0,

        OCI_ATTR_DATA_TYPE,errhp));

//若这个字段为日期型,则把其字符宽度置为30

    if(coltype[i]==SQLT_DAT) collen[i]=30;

//分配缓冲区

colbuf[i]=(text*)new text[(int)collen[i]+1];

//代码5.4.2获取字段名称

ErrorProc(errhp,OCIAttrGet(colhp,

OCI_DTYPE_PARAM, (dvoid*)&namep,

     (ub4*)&sizep,OCI_ATTR_NAME, errhp));

strncpy((char *)tempText,

(char *)namep, (size_t) sizep);

tempText[sizep] = '/0';

//把字段的名称赋予字段名称数组

ColName[i].Format("%s",tempText);

}

//代码5.5,处理SQL的第五步,定义变量

for(i=0;i<(int)col_num;i++)

{

if(status=OCIDefineByPos(stmthp,&defhp[i],

errhp,i+1,(ub1*)colbuf[i], collen[i]+1,

SQLT_STR,&ind[i],0,0, OCI_DEFAULT))

    { ErrorProc(errhp,status); return; }

}

//代码5.6,处理SQL的第六步,取值

int row=0;

while((OCIStmtFetch(stmthp,errhp,1,OCI_FETCH_NEXT,OCI_DEFAULT))!=OCI_NO_DATA)

{

   for(i=0;i<(int)col_num;i++)

    {//把获取的用户的基表的数据

//赋予字段数值数组

ColVal[row][i]=colbuf[i];     }          

    row=row+1;

}

//删除所分配的缓冲区

for(i=0;i<(int)col_num;i++)delete colbuf[i];

  

//代码5.7,把获取的数据显示到ListCtrl上

//设置ListCtrl的样式

m_listCtrl.ModifyStyle(NULL,  LVS_REPORT);

m_listCtrl.SetExtendedStyle(LVS_EX_FLATSB | LVS_EX_FULLROWSELECT

|LVS_EX_GRIDLINES);

m_listCtrl.SetFocus();

//加ListCtrl数据列的标题

int ColNumber=

m_listCtrl.GetHeaderCtrl()->GetItemCount();

//清空

for(i=0;i<ColNumber;i++)

   m_listCtrl.DeleteColumn(0);

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: