3 Replies Latest reply: Aug 14, 2012 11:33 PM by 955617 RSS

    PL/SQLの実行について

    955617
      VC++2005 MFC+OCCIにて、以下のようにエラーメッセージを取得しています。
      Oracle10g (10.2.0.3.0)

      CString OCCIWrap::GetErrorMessage(int errCode)
      {
        CString szReturn(_T(""));
        Statement* oraStmt;
        CString szSQL = _T("BEGIN :a := sqlerrm(-:v1); END;");

        try {
          // Connection* m_oraConは事前に接続済み
          oraStmt = m_oraCon->createStatement((LPCTSTR)szSQL);
          oraStmt->setInt(2, errCode);
          oraStmt->registerOutParam(1, OCCISTRING, 2048, "");
          oraStmt->executeUpdate();

          szReturn = (LPCTSTR)oraStmt->getString(1).c_str();
          m_oraCon->terminateStatement(oraStmt);
        }
        catch (SQLException& ex) {
          szReturn = ex.getMessage().c_str();
        }
        return szReturn;
      }

      これをODP.NETに書き直そうとして、以下のようにしました。

      using namespace System;
      using namespace System::Data;
      using namespace Oracle::DataAccess::Client;
      using namespace Oracle::DataAccess::Types;

      String^ ODPWrap::GetErrorMessage(int errCode)
      {
        String^ szReturn = gcnew String(L"");
        String^ szSQL = gcnew String(L"BEGIN :ret_val := sqlerrm(-:err_code); END;");

        try {
          // OracleConnection^ m_oraConは事前に接続済み
          OracleCommand^ oraCmd = gcnew OracleCommand(szSQL, m_oraCon);
          oraCmd->CommandType = CommandType::StoredProcedure;
          OracleParameter^ paramOut = oraCmd->Parameters->Add(L":ret_val", OracleDbType::Varchar2, ParameterDirection::Output);
          OracleParameter^ paramIn = oraCmd->Parameters->Add(L":err_code", OracleDbType::Int32, ParameterDirection::Input);
          paramIn->Value = errCode;

          oraCmd->ExecuteNonQuery();

          szReturn = paramOut->Value->ToString();
        }
        catch (OracleException^ e) {
          // デバッグ用
          szReturn = e->Message;
        }
        return szReturn;
      }

      実行するとOracleExceptionが発生してしまいます。
      メッセージ内容は以下でした。

      ORA-06550: 行1、列50:
      PLS-00103: 記号"("が見つかりました。 次のうちの1つが入るとき:

      begin case declare end exception exit for goto if loop mod
      null pragma raise return select update while with
      <an identifier> <a double-quoted delimited-identifier>
      <a bind variable> << close current delete fetch lock insert
      open rollback savepoint set sql execute commit forall merge
      pipe
      記号"case" は続行のために"("に代わりました。
      ORA-06550: 行1、列60:
      PLS-00103: 記号";"が見つかりました。 次のうちの1つが入るとき:

      * & = - + < / > at in is mod remainder not rem when
      <an exponent (**)> <> or != or ~= >= <= <> and or like LIKE2_
      LIKE4_ LIKEC_ between overlaps

      ODP.NETでは、このような構文は許されないのでしょうか?
      (CommandType::StoredProcedureとしている時点でアウトな気もしますが...)


      結局、以下のようなファンクションを作成して実行すればエラーメッセージを取得できました。
      CREATE OR REPLACE FUNCTION
      GETSQLERRMTEXT(err_code IN NUMBER) RETURN VARCHAR2
      IS
      ret_value VARCHAR2(2048);
      BEGIN
           ret_value := sqlerrm(-err_code);
           RETURN ret_value;
      END;

      ファンクションを作成しないで、エラーメッセージを取得する方法があれば教えてください。
      よろしくお願いします。
        • 1. Re: PL/SQLの実行について
          hamadeguchi
          お書きになっている通り
          CommandTypeをTextにすればいけると思いますが
          試されましたか?
          • 2. Re: PL/SQLの実行について
            955617
            Replyありがとうございます。
            投稿する前にCommandDbType::Textも試していたのですが、ログを取得していなかったので、
            再度実行してみたところ、以下のエラーとなりました。

            ORA-06502: PL/SQL: 数値または値のエラー: 文字列バッファが小さすぎます。が発生しました
            ORA-06512: 行1

            Outputパラメータのバッファ長の事でしょうか?
            • 3. Re: PL/SQLの実行について
              955617
              自己解決いたしました。

              変更点は2行です。
              oraCmd->CommandType = CommandType::StoredProcedure;
              OracleParameter^ paramOut = oraCmd->Parameters->Add(L":ret_val", OracleDbType::Varchar2, ParameterDirection::Output);
               ↓
              oraCmd->CommandType = CommandType::Text;
              OracleParameter^ paramOut = oraCmd->Parameters->Add(L":ret_val", OracleDbType::Varchar2, 2048, DBNull::Value, ParameterDirection::Output);

              これで、意図した動きとなりました。


              hamadeguchiさん、ヒントありがとうございました。