2012-11-27 39 views
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值爲假,但執行沒有達到第3點和第8點。

它看起來像一些內部錯誤occ但是我不確定我該如何去捕捉它。奇怪的是,這種情況發生在相同的數據上,不時發生,否則就會起作用。

P.S. MySQL版本5.0.51b,PHP 5.2.6。

P.S.S.我設法找到一個相關的問題 - Calling a Stored Procedure Within a Cursor Loop, Without Tripping the Continue Handler。正如我的程序的名稱所暗示的那樣,它從外部過程的循環內部被調用(順便說一下,它有一個循環遍歷「paths」表,另一個繼續處理程序),所以它類似於這種情況,可能是某種程度上重要。我已經嘗試了鏈接問題的解決方案,但它也沒有幫助。

找到了解決辦法,答案發布在以下。

回答

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's來控制執行流程。

看來存儲過程不喜歡什麼時候SELECT編輯成(不可用)控制檯。在我的情況下,這導致了不一致的行爲:過程在相同數據上的某些任意測試運行中放棄執行。如果有人能夠闡明這種行爲,我很樂意接受這個答案,而不是我的答案。

1

處理程序停止循環,如:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET stop = TRUE; 

是全局的整個過程。

因此,它可能會捕獲其他未找到的事件,而不是來自光標獲取,並導致循環提前退出。

嘗試使用開始結束塊只是圍繞遊標獲取,並在那裏聲明處理程序。

+0

感謝您的想法,但唉,它並沒有幫助。我發現了一個可能與之相關的bug:http://bugs.mysql.com/bug.php?id=12168(標記爲固定並在其他條件下顯示)。我打算找到解決方法。 – Stan