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

  • Post author:
  • Post category:其他



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);