【Oracle】VC6.0使用 odbc 访问 Oracle 存储过程

环境说明

系统环境

  • 系统:Windows XP
  • IDE: Microsoft Visual C++ 6.0
  • msado15.dll:
    • 文件版本: 6.2.19041.3570
    • 产品版本: 10.0.19041.3570
  • 数据源驱动程序:Oracle in OraClient11g_home1 - Oracle Datebase Client 11g Release 2 (11.2.0.1.0) for Microsoft Windows (32-Bit)
    在这里插入图片描述
    在这里插入图片描述

使用的对象 msado15.tlh

  • _ConnectionPtr m_pConnection;

    HRESULT hr = m_pConnection.CreateInstance(“ADODB.Connection”);

  • _RecordsetPtr m_pRecordset;

    m_pRecordset.CreateInstance(“ADODB.Recordset”);

  • _CommandPtr m_pCommand;

    m_pCommand.CreateInstance(“ADODB.Command”);

  • _ParameterPtr pInputParam;

    pInputParam.CreateInstance(__uuidof(Parameter));

Oracle 存储过程

Procedures

CREATE OR REPLACE PROCEDURE PRO_DISPENSER_DISPENSING 
(
  I_CHFM IN VARCHAR2  
, ERR_NO OUT NUMBER  
, ERR_MSG OUT VARCHAR2  
) AS 
BEGIN
  ERR_NO := 1;
  ERR_MSG := I_CHFM;
END PRO_DISPENSER_DISPENSING;

使用Oracle SQL Developer 调用存储过程

  DECLARE
    v_err_no NUMBER;
    v_err_msg VARCHAR2(100);
  BEGIN
    PRO_DISPENSER_DISPENSING('少莫千华', v_err_no, v_err_msg);
    DBMS_OUTPUT.PUT_LINE('Error number: ' || v_err_no);
    DBMS_OUTPUT.PUT_LINE('Error message: ' || v_err_msg);
  END;

在这里插入图片描述

VC6.0 完整代码

注意事项:以下代码可以会出现第一次调用成功,第二次调用失败的情况,建议每次调用都关闭链接,再重新打开链接再调用存储过程。

	CADOManage* adb = new CADOManage();
    LONG errorCode = adb->open();
	if (errorCode !=0)
	{
		continue;
	}
	// 调用存储过程
	errorCode = adb->execSQL2('入参1');
	if (errorCode !=0)
	{
		adb->freeRecord();
		adb->close();
		continue;
	}
	adb->freeRecord();
	adb->close();
long CADOManage::open()								
{
	//return open(param);
	string connectMode = configUtil.getValue(cfghis_unMysql_DBConnectMode);
	try
	{
		rootLogger->trace("function open start..............");
		CoInitialize(0);
		HRESULT hr = m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象
		if(SUCCEEDED(hr))
		{
            //dbType = "MYSQL";
			_bstr_t connStr;
			m_pConnection->CursorLocation=adUseClient;
				for(int i=0;i< DBCMORA_NUM;i++)
				{
					if (egOracleCoonectUI[i] == connectMode)
					{
						string strConnect;
						CString cstrConnect;
						cstrConnect =stringToCString(egOracleCoonect[i]) ;
						cstrConnect.Replace("myHost",stringToCString(ADODBparam.m_server));
						cstrConnect.Replace("myUser",stringToCString(ADODBparam.m_uid));
						cstrConnect.Replace("myPassword",stringToCString(ADODBparam.m_pwd));
						cstrConnect.Replace("myDSName",stringToCString(ADODBparam.m_data));
						if(ADODBparam.m_port == "")
							ADODBparam.m_port = 1433;
						cstrConnect.Replace("myPort",stringToCString(ADODBparam.m_port));

						strConnect = CStringTostring(cstrConnect);
						if (i== DBCMORA_ODBC1 || i==DBCMORA_OLEDBMS13 || i==DBCMORA_OLEDBOracle1)
						{
							m_pConnection->Open(_bstr_t(strConnect.c_str()),(_bstr_t)ADODBparam.m_uid.c_str(),(_bstr_t)ADODBparam.m_pwd.c_str(),adConnectUnspecified);
						}
						else if (i== DBCMORA_ODBC3)
						{
								m_pConnection->Open(_bstr_t(strConnect.c_str()),(_bstr_t)_T(""),(_bstr_t)_T(""),adModeUnknown);
						}
						else
						{
							m_pConnection->Open(_bstr_t(strConnect.c_str()),(_bstr_t)_T(""),(_bstr_t)_T(""),adConnectUnspecified);

						}
						break;
					}
				}	
			bOpen= true;
			m_pRecordset.CreateInstance("ADODB.Recordset");
			m_pCommand.CreateInstance("ADODB.Command");
			m_pCommand->ActiveConnection = m_pConnection;
		}
	}
	catch(_com_error e)///捕捉异常
	{
		string errormessage;
		errormessage = "连接ADO数据库失败!\r错误信息:";
		errormessage +=e.ErrorMessage();
		rootLogger->fatal(errormessage);
	//	AfxMessageBox(errormessage.c_str());///显示错误信息
		//bOpen= false;
        return ER_DB_CONNECT;
	}
	rootLogger->trace("function open end..............");
	return 0;
}		
long CADOManage::execSQL2(const string &sqlText)
{
	try{	
		rootLogger->trace("function execSQL start..............");
		mute->Lock();
		int nRet = 0;
		
		if (sqlText == "")
		{
			rootLogger->warn("no SQL text!..............");
			mute->Unlock();
			return WM_NO_SQLTEXT;
		}
		
		freeRecord();
		rootLogger->debug("sqlText = " + sqlText);
		//设置命令类型
		m_pCommand->CommandType = adCmdStoredProc;
		//设置存储过程名称
		m_pCommand->CommandText =_bstr_t("pro_dispenser_dispensing");
		m_pCommand->put_CommandTimeout(60);
		_ParameterPtr pInputParam,pOutputParam1,pOutputParam2;
		pInputParam.CreateInstance(__uuidof(Parameter));
		pOutputParam1.CreateInstance(__uuidof(Parameter));
		pOutputParam2.CreateInstance(__uuidof(Parameter));
		//设置入参 i_cfhm 名称、数据类型、输入/输出、长度、内容
        pInputParam = m_pCommand->CreateParameter(_bstr_t("i_cfhm"), adVarChar, adParamInput, sqlText.length(), sqlText.c_str());
        pInputParam->Value = _variant_t(sqlText.c_str());
        //设置出参1 err_no 名称、数据类型、输入/输出、长度
		pOutputParam1 = m_pCommand->CreateParameter(_bstr_t("err_no"), adInteger, adParamOutput,10);
		//设置出参2 err_msg 名称、数据类型、输入/输出、长度
        pOutputParam2 = m_pCommand->CreateParameter(_bstr_t("err_msg"), adVarChar, adParamOutput, 1024);
		pOutputParam2->Size = 1024;
		//添加入参1 到 命令
		m_pCommand->Parameters->Append(pInputParam);
		//添加入出参1 到 命令
        m_pCommand->Parameters->Append(pOutputParam1);
        //添加入出参2 到 命令
        m_pCommand->Parameters->Append(pOutputParam2);
        //以存储过程的形式adCmdStoredProc 执行命令
		m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdStoredProc); 
		
		_variant_t errNoValue = pOutputParam1->Value;
		_variant_t errMsgValue = pOutputParam2->Value;

		// 转换为具体的类型
		long errNo = errNoValue.lVal;
		CString temp;
		temp.Format(_T("%ld"), errNo);
		MessageBox(NULL, temp, _T("err_no"), MB_OK);
		if (errMsgValue.bstrVal != NULL)
		{
			_bstr_t errMsg = errMsgValue.bstrVal;
			string temp(errMsg);
		}

		m_pCommand
		->Parameters->Release();
		pInputParam->Release();
		pOutputParam1->Release();
		pOutputParam2->Release();
		
		mute->Unlock();
		rootLogger->trace("function execSQL end..............");
	}
	catch (_com_error e) {
        string errormessage = e.ErrorMessage();        
		rootLogger->error("failed to execute SQL:" + errormessage);
		rootLogger->error("failed sql = " + sqlText);
		mute->Unlock();
		return ER_EXECUTE_SQL;
	}
	return 0;
}

报错情况

使用 m_pCommand->Execute(NULL, NULL,adCmdStoredProc)调用Oracle存储过程时遇到了异常。

  • 数据源驱动程序: Oracle in OraClient12Home1_32bit

这种情况可能是由于不同版本的Oracle驱动与msado15.dll之间的兼容性问题导致的。不同版本的驱动程序和库文件可能具有不同的接口和行为,因此在使用不同版本的驱动程序时可能会出现不兼容的情况。
解决此问题的一种方法是确保使用的Oracle驱动程序msado15.dll版本兼容。您可以尝试以下解决方案:

  1. 更换msado库 - 确认您的代码中使用的是与Oracle驱动程序版本相匹配的msado15.dll库文件。如果您使用的是Oracle in OraClient12Home1_32bit驱动程序,尝试使用与该驱动程序版本相对应的msado15.dll库文件。
  2. 如果您无法找到与Oracle驱动程序版本完全匹配的msado15.dll库文件,可以尝试升级或降级Oracle驱动程序版本,如:Oracle in OraClient11g_home1,以确保与可用的msado15.dll库文件兼容。
  3. 另外,您还可以考虑使用其他的数据库连接库或方法来连接和调用Oracle存储过程。例如,可以尝试使用Oracle提供的官方的ODBC驱动程序或其他第三方的数据库连接库,以避免与msado15.dll版本不兼容的问题。

Microsoft C++ 异常: long,位于内存位置

0x75FOD982 处(位于 OracleTest.exe 中)发的异常: Microsoft C++ 异常: long,位于内存位置 0x00E6D88C 处。

在这里插入图片描述

0x75FOD982 处(位于 OracleTest.exe 中)发的异常: Microsoft C++ 异常: long,位于内存位置 0x0133D9A4 处。

在这里插入图片描述