刚接触Oracle一个星期不到, 为了公司的项目勿勿学习了一下Oracle,原以为基本上搞定表空间、模式之类Sql Server用不到的概念,再学会基本的PL SQL语句就Ok了。用ADO连接Oracle的返回简单数据类型的存储过程也搞得定,心里不禁洋洋得意。我是天才,我怕谁? 上头说,电信的项目搞得定不?(电信是用Oracle)。我很豪爽地答了句:没问题!可一接到电信的存储过程就傻眼了,Package中定义了返回结果集的存储过程,而且包头给你看,包体却木有。试了很久,在csdn上问没人答。也看到一些网上的教程,不管是中文的还是外文的都木有用,这下就郁闷了。
不行,我得自己建个这样的包试试。包定义是这样的形式:
CREATE OR REPLACE PACKAGE PK_ConsolManager_LoginCheck AS/**//****************************************************************************** NAME: PK_ConsolManager_LoginCheck PURPOSE: REVISIONS: Ver Date Author Description --------- ---------- --------------- ------------------------------------ 1.0 2005-11-25 1. Created this package.******************************************************************************/TYPE T_CURSOR IS REF CURSOR; PROCEDURE MyProcedure(Param1 IN NUMBER, Param3 Out Number, Param2 OUT T_CURSOR);END PK_ConsolManager_LoginCheck ;/包体定义:
CREATE OR REPLACE PACKAGE BODY PK_ConsolManager_LoginCheckASPROCEDURE MyProcedure(Param1 IN NUMBER,Param3 Out Number, Param2 OUT T_CURSOR) IS BEGIN Open Param2 FOR SELECT LoginName, Password from ConsoleManager where SerialRights = Param1; Param3 := Param1;END;END;/用C# 试试ADO.net访问它,so easy,因为ADO.net有OracleTypes.Cursor类型,马上就可以得到答案!这里顺便提醒用ADO.net的兄弟们,连接字符串不易过长,要不然会有异常的 :)
再用网上的方法试试,就是把最后一个返回REF Cursor的参数省略,然后执行返回RecordSet的函数试试。
// OracleCursorApp.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <ole2.h>#include <stdio.h>#include "conio.h"//Function declarationinline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};void ExecuteSql(VOID);void PrintProviderError(_ConnectionPtr pConnection);/**////////////////////////////////////////////////////////////// //// Main Function //// ///**////////////////////////////////////////////////////////////void main(){ HRESULT hr = S_OK; if(FAILED(::CoInitialize(NULL))) return; ExecuteSql(); //Wait here for the user to see the output. printf("\n\n按任意键继续"); getch(); ::CoUninitialize(); }/**////////////////////////////////////////////////////////////// //// ExecuteSql Function //// ///**////////////////////////////////////////////////////////////VOID ExecuteSql(VOID){ HRESULT hr = S_OK; // Define ADO object pointers. // Initialize pointers on define. // These are in the ADODB:: namespace. _RecordsetPtr pRs = NULL; _CommandPtr pCmd = NULL; _ParameterPtr pPrmParam1 = NULL; _ParameterPtr pPrmParam3 = NULL; _ConnectionPtr pConnection = NULL; _bstr_t strCnn("Provider=OraOLEDB.Oracle;Data Source=Console;User Id=aol;Password=123;"); _bstr_t strMessage, strAuthorID; int intParam1; VARIANT vtParam1; VARIANT vtParam3; try { //Open a Connection. TESTHR(pConnection.CreateInstance(__uuidof(Connection))); hr = pConnection->Open(strCnn,"","",adConnectUnspecified); pConnection->CursorLocation = adUseClient; //Open Command Object with one Parameter TESTHR(pCmd.CreateInstance(__uuidof(Command))); pCmd->CommandText = "PK_ConsolManager_LoginCheck.MyProcedure"; pCmd->CommandType = adCmdStoredProc; //Get parameter value and append parameter printf("输入: "); scanf("%d",&intParam1); //Define Integer/variant. vtParam1.vt = VT_I2; vtParam1.iVal = intParam1; pPrmParam1 = pCmd->CreateParameter("Param1",adInteger,adParamInput,sizeof(int),vtParam1); pCmd->Parameters->Append(pPrmParam1); pPrmParam1->Value = vtParam1; vtParam3.vt = VT_I2; pPrmParam3 = pCmd->CreateParameter("Param3", adInteger, adParamOutput, sizeof(int), vtParam3); pCmd->Parameters->Append(pPrmParam3); //Create Recordset by executing the command //printf("%d", pRs->GetRecordCount()); pCmd->ActiveConnection = pConnection; pRs = pCmd->Execute(NULL,NULL,adCmdStoredProc); _bstr_t bstrLoginName; bstrLoginName = pRs->Fields->Item["LoginName"]->Value; printf("登录名: %s \n", (LPCSTR) bstrLoginName); vtParam3 = pCmd->Parameters->Item["Param3"]->Value; printf("%d", vtParam3.intVal); } catch(_com_error &e) { _bstr_t bstrSource(e.Source()); _bstr_t bstrDescription(e.Description()); PrintProviderError(pConnection); printf("\n 源 : %s \n 描述 : %s \n",(LPCSTR)bstrSource,(LPCSTR)bstrDescription); } if (pRs) if (pRs->State == adStateOpen) pRs->Close(); if (pConnection) if (pConnection->State == adStateOpen) pConnection->Close();}/**////////////////////////////////////////////////////////////// //// PrintProviderError Function //// ///**////////////////////////////////////////////////////////////VOID PrintProviderError(_ConnectionPtr pConnection){ // Print Provider Errors from Connection object. // pErr is a record object in the Connection's Error collection. ErrorPtr pErr = NULL; long nCount = 0; long i = 0; if( (pConnection->Errors->Count) > 0) { nCount = pConnection->Errors->Count; // Collection ranges from 0 to nCount -1. for(i = 0; i < nCount; i++) { pErr = pConnection->Errors->GetItem(i); printf("Error number: %x\n Error Description: %s\n", pErr->Number,(LPCSTR) pErr->Description); } }}再试,得到异常:
输入: 0
Error number: 80040e14
Error Description: ORA-06550: 第 1 行, 第 7 列:
PLS-00306: 调用 'MYPROCEDURE' 时参数个数或类型错误
ORA-06550: 第 1 行, 第 7 列:
PL/SQL: Statement ignored
源 : OraOLEDB
描述 : ORA-06550: 第 1 行, 第 7 列:
PLS-00306: 调用 'MYPROCEDURE' 时参数个数或类型错误
ORA-06550: 第 1 行, 第 7 列:
PL/SQL: Statement ignored
按任意键继续...
网上的方法还是没用,郁闷至极啊!!!
就这样试了N次,郁闷了N天,终于有一天人品爆发,我把连接字符串改成:
_bstr_t strCnn("Provider=MSDAORA.1;Data Source=Console;User Id=aol;Password=123;");
结果得答案:
输入: 0
登录名: Jeremy
0
按任意键继续...
成功了~!
真想说句我kao!!!
这就是我用ADO操作Oracle结果集的心得。