1

「バインド変数が存在しません」という ORA-1006 エラーが発生します

以下は私のコードスニペットです

create or replace procedure bindFailure(In_cntAcct, In_custAcct, In_CardNo, In_Code) AS
  txnHdl INTEGER;
begin
   txnHdl := dbms_sql.open_cursor;
   sqlStmt := 'select * from txn t'
              || ' where t.cntAcct  = :IN_CNTACCT '
              || ' and   t.custAcct = :IN_CUSTACCT '
              || ' and   t.cardNo   = :IN_CARDNO '
              || ' and   t.Code     = :IN_CODE ';

   dbms_sql.parse(txhHdl, sqlStmt, DBMS_SQL.NATIVE);

   dbms_sql.bind_variable(txnHdl, ':IN_CNTACCT'  , In_cntAcct);
   dbms_sql.bind_variable(txnHdl, ':IN_CUSTACCT' , In_custAcct);
   dbms_sql.bind_variable(txnHdl, ':IN_CARDNO'   , In_CardNo);
   dbms_sql.bind_variable(txnHdl, ':IN_CODE'     , In_Code);

   dbms_sql.execute(txnHdl);

   .... /* In actual code we use fetch rows */

end;
/

ここに、cntAcct、、およびcustAcctNumbercardNoCodeVarchar2

ほとんどの場合、上記のコードは正常に動作しますが、100K に 1 回、このコードが「バインディング変数が存在しません」というエラーで失敗することはめったにありません。

同じ入力とプロセスを使用すると、正常に機能します。なぜこの問題が発生しているのか、私にはわかりません。これについて私を助けてください。

注: 上記のコードはスニペットであり、タイプミスの問題があれば無視してください。

ありがとう、プレムチャンドC

4

1 に答える 1

1

回避策として、動的 SQL の使用を避けることができます。SELECT リストでアスタリスク (" *") をコーディングする代わりに、返される列名を指定します。また、引数変数を SQL テキストに含めます。Oracle は自動バインドを行います。

CREATE OR REPLACE PROCEDURE ... 
IS
  CURSOR lcsr_txn IS
  SELECT t.cntAcct
       , t.custAcct
       , t.cardNo
       , t.Code
    FROM txn t
   WHERE t.cntAcct  = IN_cntAcct
     AND t.custAcct = IN_custAcct
     AND t.cardNo   = IN_cardNo
     AND t.Code     = IN_Code
  ;
BEGIN
  FOR lrec IN lcsr_txn LOOP
    -- code to process rows goes here e.g.
    DBMS_OUTPUT.PUT_LINE("cntAcct="||lrec.cntAcct);
  END LOOP;
END;

元の答え

それがヘッドスクラッチャーです。このコードには明らかな問題はありません。(手順がほとんどの場合に機能することを考えると、パラメーターのデータ型が指定されており、これらがすべて IN パラメーターであると仮定します。)

解析が機能し、カーソル ハンドルが返されることは考えられますが、bind_variable へのすべての呼び出しが完了する前にカーソルが無効になります。しかし、それはORA-1006以外の例外になると思います。

txnHdl が何らかの形で異常を起こし、別のカーソルを指している場合、bind_variableプロシージャが間違ったカーソルで呼び出されると、ORA-1006 例外が発生することがわかりました。(しかし、それはあなたの手順ではなく、Oracleコードの深刻なバグです。しかし、私はそのエラーに遭遇したことはなく、MySQLのいずれかでこのようなことをチェックする必要はありませんでした.

これをデバッグするには、めったに発生しないため、Oracle サポートにケースをオープンし、例外 ORA-1006 が発生するたびにトレース/ダンプを収集できるかどうかを確認します。(私はこれまでにSET EVENTを実行したことがありません。それが可能かサポートされているかさえわかりません。これは「クライアント側」の例外かもしれませんが、サーバー上で実行されているPL/SQLブロックでは、利用できると思います.しかし、特に本番データベースサーバーでは、Oracleサポートのガイダンスの下でこれを行います.)

Q:

bind_variable例外をスローしているのはプロシージャ内の呼び出しであることをどの程度確信していますか。その ORA-1006 例外は ORA-06502 例外内にラップされていますか? (そうなると思います。そうでない場合、実際には、例外を発生させているプロシージャに変数をバインドしているJDBCセッションである可能性があります。)

プロシージャへの入力パラメータごとにローカル プロシージャ変数を作成し、入力パラメータをローカル プロシージャ変数に代入したくなるでしょう。また、EXCEPTION ハンドラーを挿入したくなるので、問題を監査できます。

CREATE OR REPLACE PROCEDURE bindFailure
( In_cntAcct  NUMBER
, In_custAcct NUMBER
, In_CardNo   VARCHAR2
, In_Code     VARCHAR2  
) AS
  txnHdl INTEGER;
  xn_cntacct   txn.cntAcct%TYPE;
  xn_custacct  txn.custAcct%TYPE;
  xn_cardno    txn.cardNo%TYPE;
  xn_code      txn.Code%TYPE;
  bind_variable_does_not_exist EXCEPTION;
  PRAGMA EXCEPTION_INIT (bind_variable_does_not_exist, 1006);
BEGIN
  xn_cntAcct  := IN_CntAcct;
  xn_custAcct := IN_CustAcct;
  xn_cardno   := IN_CardNo;
  xn_code     := IN_Code;

  txnHdl := dbms_sql.open_cursor;
  sqlStmt := 'select * from txn t'
             || ' where t.cntAcct  = :IN_CNTACCT '
             || ' and   t.custAcct = :IN_CUSTACCT '
             || ' and   t.cardNo   = :IN_CARDNO '
             || ' and   t.Code     = :IN_CODE ';

  dbms_sql.parse(txnHdl, sqlStmt, DBMS_SQL.NATIVE);
  dbms_sql.bind_variable(txnHdl, ':IN_CNTACCT'  , xn_cntacct);
  dbms_sql.bind_variable(txnHdl, ':IN_CUSTACCT' , xn_custacct);


EXCEPTION 
  WHEN bind_variable_does_not_exist THEN
    -- auditing here
    RAISE;
  WHEN OTHERS THEN
    RAISE;
END;
于 2013-07-23T19:50:58.033 に答える