2012-12-02 17 views
5

मेरे पास निम्न प्रक्रिया है जो एक अप्रत्यक्ष ग्राफ में किनारे (सिंगलजेज) और किनारे सेट (एजसेट) लेने वाले चक्रों का पता लगाने के लिए है। दो और तर्क हैं, बाएं_सेट (जो आवश्यक किनारों को रिकर्सन में पारित करने के लिए है) और चक्रीय (जो एक बूलियन मान है जो अंततः यह निर्धारित करता है कि ग्राफ चक्रीय था या नहीं।MySQL रिकर्सिव चक्र पहचान प्रक्रिया

किसी कारण से, पहचान अतीत पहले प्रत्यावर्तन काम नहीं करता है यहाँ टिप्पणियां विवरण समझा साथ कोड है:।

निम्नलिखित कार्य MySQL में ME द्वारा लागू किया गया (भ्रम से बचने के):

-concat_set(): रिटर्न एक खाली सेट

के मामले में गलत सेट 'के लिए लेखांकन के दो सेटों का समापन

-remove_first(): किनारों के नोड्स देता है, किनारों के बीच सीमांकक है ':' तो एक बढ़त इस '12 की तरह दिखता है: 15 'सेट

-get_left_node()/get_right_node से पहले सदस्य को हटा

CREATE PROCEDURE `is_cyclic`(
IN `singleedge` VARCHAR(15), 
IN `edgeset` VARCHAR(1024), 
IN 'left_set' VARCHAR(512), 
OUT `cyclic` BOOLEAN) 

BEGIN 
DECLARE se_left VARCHAR(5); 
DECLARE es_left VARCHAR(5); 
DECLARE se_right VARCHAR(5); 
DECLARE es_right VARCHAR(5); 
Call get_left_node(singleedge, se_left); 
Call get_left_node(SUBSTRING_INDEX(edgeset, ',', 1), es_left); 
Call get_right_node(singleedge, se_right); 
Call get_right_node(SUBSTRING_INDEX(edgeset, ',', 1), es_right); 



--is edgeset emptY? 
    IF LENGTH(edgeset)= 0 AND LENGTH(left_set) = 0 THEN 
     BEGIN 

      SET cyclic= false; 

     END;  

--are singeeledge and first edge in edgeset the same?   
    ELSEIF ((se_left = es_left 
     OR se_left= es_right) 
     AND(se_right = es_left 
     OR se_right = es_right)) THEN 
        BEGIN 
      set cyclic= true; 
         END; 


--do singleedge and first edge in edgeset share any vertices?  
    ELSEIF se_left = es_left 
     OR se_left= es_right 
     OR se_right = es_left 
     OR se_right = es_right 
     THEN 
     --check for all possiblities 
      BEGIN 

       --if left vertex of singleedge and left vertex of current edge in front of edgeset are the same    
       IF se_left=es_left THEN 
            BEGIN 
            --test if the edge of combined uncommon vertices (forming concat(se_right,':',es_right)) exists in the remaining edgeset concatanated with the left_set 
            CALL is_cyclic(concat(se_right,':',es_right),concat_set(left_set,remove_first(edgeset)), '', cyclic); 
            --if the recursion returns cyclic=false, then remove the considered edge from edgeset and continue trying to match the original singleedge with the rest of edgeset 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
             END IF; 
            END; 
       ELSEIF se_left= es_right THEN 
            BEGIN 
            CALL is_cyclic(concat(se_right,':',es_left), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
            END; 
       ELSEIF se_right=es_left THEN 
            BEGIN 
            CALL is_cyclic(concat(se_left,':',es_right), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
            END; 
       ELSE 
            BEGIN 
            CALL is_cyclic(concat(se_left,':',es_left), concat_set(left_set, remove_first(edgeset)), '', cyclic); 
            IF cyclic=false THEN 
             CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
            END IF; 
             END; 
           END IF; 


      END;  


     ELSE 
      BEGIN 
       --if the current edge being considered from the edgeset does not contain any vertex in common with singleedge, set it aside into left_set and call is_cyclic recurisvely with the edge removed 
       SET left_set = concat_set(left_set, SUBSTRING_INDEX(edgeset, ',', 1)); 
       CALL is_cyclic(singleedge, remove_first(edgeset), left_set, cyclic); 
       END; 

    END IF; 
END 
+1

मैं बस एक लूप में रिकर्सन को खोलना चाहता हूं। यह कोड को थोड़ा उलझन में डाल सकता है, लेकिन यह पहले से ही बहुत बदसूरत है। – siride

उत्तर

2

कोशिश इस mysql चर रीसेट करने के लिए: max_sp_recursion_depth आदेश ऊपर को क्रियान्वित करने के लिए अपने प्रक्रिया कॉल के बाद thread_stack

SET SESSION max_sp_recursion_depth = 10; 
SET SESSION thread_stack = 250000; 

,। क्रमशः दोनों कथन निष्पादित करें। आपकी आवश्यकता के अनुसार thread_stack के आकार को बढ़ाएं।

+0

यह वास्तव में काम करता था, मैं इस तरह की रिकर्सन गहराई को पहले सेट कर रहा था: 'सेट ग्लोबल max_sp_recursion_depth = 150; क्या दोनों के बीच कोई अंतर है? बड़े सेट पर चक्र की जांच करते समय मुझे निम्न त्रुटि भी मिलती है: '# 1436 - थ्रेड स्टैक ओवररन 'क्या मुझे मैन्युअल रूप से एक बड़ा स्टैक निर्दिष्ट करना चाहिए या क्या यह कोड को ठीक करना और इसे रोकना बेहतर है? – Mike

+0

वैश्विक कीवर्ड वैरिएबल को वैश्विक रूप से रीसेट करने का मतलब है कि यह 150 तक रीसेट करता है जब तक कि आप mysql सेवा को पुनरारंभ नहीं करते। और यह अनिवार्य नहीं है कि आपने वैश्विक स्तर पर इस चर को ट्रेससेट किया है, इसलिए इसके बजाय आप प्रति सत्र उस चर को रीसेट कर सकते हैं। –

+0

मुझे कोड को कभी भी थ्रेड स्टैक ओवररन त्रुटि को फेंकने के बिना काम नहीं किया गया। – Mike