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。這樣就在本工程中加入了一個可以接收輸入用戶信息的對話框類。
表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文件的宏定義部分。
表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); |
||||||||||||||||||||||||||||||||||||||||||||||||||||
OCI接口簡介及其在VC++中的應用(中)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.