2013-05-16 5 views
5

मेरे पास निम्न लेआउट में संग्रहीत नेटवर्क में सबनेट्स की एक बड़ी सूची है। इसका उपयोग संपत्तियों को स्टोर करने के लिए एक मास्टर टेबल के रूप में किया जाता है जिसका प्रयोग नियमित अंतराल पर पाइथन-स्क्रिप्ट द्वारा स्थिति की जांच के लिए किया जाएगा।पोस्टग्रेएसक्यूएल व्यक्तिगत पते में सीडर का विस्तार

CREATE TEMP TABLE tmp_networks (
    network cidr PRIMARY KEY 
); 

चलें मान अपने प्रदर्शन के लिए इन मूल्यों के साथ भरा:

  • 10.0.0.0/8
  • 10.0.1.0/24
  • 192.168.0.0/24

जब मैं स्क्रिप्ट चलाता हूं, तो पाइथन-स्क्रिप्ट किसी भी ओवरलैप को हटाने के लिए निम्न क्वेरी निष्पादित करेगी:

SELECT network 
    FROM tmp_networks 
    WHERE NOT EXISTS (
     SELECT network 
     FROM tmp_networks n 
     WHERE n.network >> tmp_networks.network 
); 

यह एक छोटे से मुद्दे को छोड़कर, महान काम करता है; मेरे पास व्यक्तिगत पतों की एक सूची भी है जिसे नौकरी से बाहर रखा जाना चाहिए।

CREATE TEMP TABLE tmp_except (
    address inet PRIMARY KEY 
); 

चलें यह मान दिए गए पते में शामिल हैं::

  • 10.0.0.100
  • 192.168.0.10

अब, मैं नाकाम रहे हैं यह भी डेटाबेस में एक मेज है डेटाबेस आउटपुट से इन शानदार पते को हटाने के लिए एक अच्छी विधि खोजने के लिए। मेरे विचार में, समाधान होगा की तरह कुछ:

  • सभी सबनेट
  • चयन यदि कोई अपवाद पता सबनेट भीतर पाया जाता है, छोटे टुकड़ों में विभाजित सबनेट जब तक एक अपवाद पता हटाया जा सकता है और अन्य सभी पते

मैंने जांच करने की कोशिश की है कि शुद्ध PostgreSQL में ऐसा कुछ करना संभव है, लेकिन इसे हल करने के किसी भी तरीके को खोजने में विफल रहे हैं। इस बात के बारे में कोई संकेतक कैसे हल किया जाना चाहिए?

+0

आपकी क्वेरी से आप क्या परिणाम चाहते हैं? क्या यह हमेशा * पते (/ 32) * है या यह * नेटवर्क पते यदि संभव हो और केवल पते, अगर कोई अपवाद है *? – Beryllium

+0

हाय, यदि संभव हो तो मैं नेटवर्क पते को छोड़कर या/32 यदि कोई बड़ा ब्लॉक मौजूद नहीं है। – agnsaft

उत्तर

5

मैं इसे दो कार्यों के साथ संपर्क करूंगा। पहला फ़ंक्शन एक सिडर और अपवाद पता लेता है, और सिडर का एक सेट देता है जो मूल सिडर के अपवाद पते के बराबर होता है। यह फ़ंक्शन सिडर को दो हिस्सों में विभाजित करके काम करता है, और उसके बाद आधे से अपवाद पते को दोबारा हटा देता है। अधिक परिष्कृत एल्गोरिदम कुछ अनावश्यक विभाजन से बच सकता है। सरल समारोह इस तरह दिखता है:

इस समारोह के साथ
CREATE OR REPLACE FUNCTION split_cidr(net cidr, exc inet) returns setof cidr language plpgsql AS $$ 
DECLARE 
    r cidr; 
    lower cidr; 
    upper cidr; 
BEGIN 
    IF masklen(net) >= 32 THEN RETURN; END IF; 
    lower = set_masklen(net, masklen(net)+1); 
    upper = set_masklen((lower | ~ netmask(lower)) + 1, masklen(lower)); 
    IF exc << upper THEN 
    RETURN NEXT lower; 
    FOR r IN SELECT * from split_cidr(upper, exc) 
    LOOP RETURN NEXT r; 
    END LOOP; 
    ELSE 
    FOR r IN SELECT * from split_cidr(lower, exc) 
    LOOP RETURN NEXT r; 
    END LOOP; 
    RETURN NEXT upper; 
    END IF; 
    RETURN; 
END $$; 

सशस्त्र, एक तो नेटवर्क सूची उन नेटवर्कों कि एक अपवाद पते निहित करने के लिए इसे लागू करने के माध्यम से पुनरावृति सकता है। निम्न फ़ंक्शन उन नेटवर्क पतों की सूची को विभाजित करता है जिनमें अपवाद और वे नहीं हैं। जो लोग वापस नहीं आते हैं, वे उपर्युक्त कार्य करते हैं। यह उस मामले से निपटता नहीं है जहां नेटवर्क में अपवाद पते से अधिक होता है।

CREATE OR REPLACE FUNCTION DOIT() RETURNS Setof cidr language plpgsql AS $$ 
DECLARE 
r cidr; 
x cidr; 
z inet; 
BEGIN 
-- these are the rows where the network has no exceptions 
FOR r in SELECT network FROM tmp_networks n WHERE NOT EXISTS (
    SELECT address FROM tmp_except WHERE address << n.network) 
LOOP RETURN NEXT r; 
END LOOP; 

-- these are the rows where the network has an exception 
FOR r,z in SELECT network, address from tmp_networks full join tmp_except on true where address << network 
LOOP 
    FOR x IN SELECT * FROM split_cidr(r, z) 
    LOOP RETURN NEXT x; 
    END LOOP; 
END LOOP; 
END $$; 

मैं एक ही अपवाद पते से split_cidr संशोधित अपवाद पतों की एक सरणी ले जाने की बजाय, और फिर एक सरणी में प्रत्येक नेटवर्क के लिए अपवाद के योग और के लिए split_cidr_array फोन करके नेटवर्क प्रति एकाधिक अपवाद पतों के मामले दृष्टिकोण होगा नेटवर्क और अपवादों की इसकी सरणी।

संबंधित मुद्दे