4

カーソルを使用してテーブル内の行を処理するストアドプロシージャがあります。この手順はほとんどの場合機能しますが、完全に実行されない場合もあります。特定の行と変数を専用のデバッグテーブルに記録する、コードに埋め込まれた単純なデバッグ機能があるため、これを知っています。最も興味深いのは、PHPから実行しているときに問題が常に発生することです。mysqlクライアントを使用する場合、この問題は発生しません。

手順(ここでは少し短縮して示しています)は次のとおりです。

CREATE PROCEDURE findnextedge(IN lastid BIGINT)
findnext_context:BEGIN
  DECLARE stop BOOLEAN DEFAULT FALSE;
  DECLARE count INT DEFAULT 0;
  DECLARE cur_fid BIGINT DEFAULT 0;
  DECLARE cur_pid1 BIGINT DEFAULT 0;
  DECLARE cur_pid2 BIGINT DEFAULT 0;
  DECLARE cur CURSOR FOR SELECT fid, pid1, pid2 FROM edges WHERE pid1 = lastid;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET stop = TRUE;

  CALL debuglog(0, 'findnextedge', 'lastid', lastid, NULL, NULL, NULL, NULL);
  SELECT SQL_CALC_FOUND_ROWS fid FROM edges WHERE pid1 = lastid;
  SET count = FOUND_ROWS();
  CALL debuglog(1, 'findnextedge', 'count', count, NULL, NULL, NULL, NULL);
  IF count = 0 THEN
    DELETE FROM paths WHERE pid1 = lastid AND pid2 = 0;
    SELECT COUNT(*) INTO count FROM paths WHERE pid2 = 0;
    CALL debuglog(2, 'findnextedge', 'count', count, NULL, NULL, NULL, NULL);
    IF count = 0 THEN
      SET @count = 1;
    END IF;
    LEAVE findnext_context;
  END IF;

  DELETE FROM paths WHERE pid1 = lastid AND pid2 = 0 ORDER BY pid1 LIMIT 1;

  OPEN cur;
  CALL debuglog(6, 'findnextedge', 'open', TRUE, NULL, NULL, NULL, NULL);
  REPEAT
    FETCH cur INTO cur_fid, cur_pid1, cur_pid2;
    CALL debuglog(7, 'findnextedge', 'stop', stop, NULL, NULL, NULL, NULL);
    IF stop = FALSE THEN

      CALL debuglog(3, 'findnextedge', 'cur_fid', cur_fid, 'cur_pid1', cur_pid1, 'cur_pid2', cur_pid2);

      // DO MAIN JOB
      // ...

      CALL debuglog(5, 'findnextedge', NULL, NULL, NULL, NULL, NULL, NULL);

    END IF;
    CALL debuglog(8, 'findnextedge', 'stop', stop, NULL, NULL, NULL, NULL);
    UNTIL stop = TRUE
  END REPEAT;

  CLOSE cur;
END;

問題が発生した場合に生成される出力全体:

point   context name1   value1  name2   value2  name3   value3  counter time
    0   findnext    lastid  0   NULL    NULL    NULL    NULL    0   2012-11-27 18:29:56
    1   findnext    count   1   NULL    NULL    NULL    NULL    1   2012-11-27 18:29:56
    6   findnext    open    1   NULL    NULL    NULL    NULL    2   2012-11-27 18:29:56
    7   findnext    stop    0   NULL    NULL    NULL    NULL    3   2012-11-27 18:29:56

ログによると、ポイント7では、カーソル値をフェッチした直後stopはfalseですが、実行はポイント3にも8にも到達しません。

内部エラーが発生しているようですが、どうすればトラップできるかわかりません。不思議なことに、これはまったく同じデータで時々発生し、それ以外の場合は機能します。

PS MySQLバージョン5.0.51b、PHP5.2.6。

PSS私は関連する質問を見つけることができました-続行ハンドラーをトリップせずに、カーソルループ内でストアドプロシージャを呼び出します。私のプロシージャの名前が示すように、外部プロシージャのループ内から呼び出されるため(ちなみに、「パス」テーブルを介したループと別の続行ハンドラがあります)、これらの状況に似ている可能性があります。どういうわけか重要です。リンクされた質問から解決策を試しましたが、どちらも役に立ちませんでした。

解決策が見つかりました。答えは以下に掲載されています

4

2 に答える 2

1

次のように、ループを停止するハンドラー。

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET stop = TRUE;

手順全体に対してグローバルです。

その結果、カーソルフェッチからではなく、他の見つからないイベントをキャッチし、ループを早期に終了させる可能性があります。

カーソルフェッチのすぐ近くで開始終了ブロックを使用して、そこでハンドラーを宣言してみてください。

于 2012-11-27T16:08:46.110 に答える
0

私は問題を解決しましたが、それがどのように行われるかは私には非常に奇妙に思えます。

台詞:

SELECT SQL_CALC_FOUND_ROWS fid FROM edges WHERE pid1 = lastid;
SET count = FOUND_ROWS();

簡略化されたものに置き換えられました:

SELECT COUNT(*) INTO count FROM edges WHERE pid1 = lastid;

そして、これは欠陥なしで動作します。

同じものが最初に2行でコーディングされた理由は、最初にデバッグテーブルがなく、を介して実行フローを制御したためSELECTです。

何かが(利用できない)コンソールに取り込まれると、ストアドプロシージャは気に入らないようSELECTです。私の場合、これは一貫性のない動作につながりました。同じデータでの任意のテスト実行で、プロシージャが実行をドロップしました。誰かがそのような行動に光を当てることができれば、私は私の代わりにその答えを受け入れてうれしいです。

于 2012-11-27T19:46:38.723 に答える