Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

CIDR चुनें जो IP की रेंज में हो

IP पतों को डॉटेड क्वाड नोटेशन में VARCHAR . में स्टोर करना उन्हें संग्रहीत करने का सबसे इष्टतम तरीका नहीं है, क्योंकि डॉटेड-क्वाड 32 बिट अहस्ताक्षरित पूर्णांक का मानव अनुकूल प्रतिनिधित्व है जो स्वयं को डेटाबेस अनुक्रमण के लिए उधार नहीं देता है। लेकिन कभी-कभी यह मौलिक रूप से अधिक सुविधाजनक होता है, और छोटे पैमाने पर, यह तथ्य कि प्रश्नों के लिए टेबल स्कैन की आवश्यकता होती है, आमतौर पर कोई समस्या नहीं होती है।

MySQL स्टोर्ड फंक्शन्स एक साधारण फंक्शन के पीछे अपेक्षाकृत जटिल लॉजिक को एनकैप्सुलेट करने का एक अच्छा तरीका है जिसे एक क्वेरी में संदर्भित किया जा सकता है, संभावित रूप से आसानी से समझने वाले प्रश्नों की ओर ले जाता है और कॉपी / पेस्ट त्रुटियों को कम करता है।

तो, यहाँ एक संग्रहीत कार्य है जिसे मैंने लिखा है जिसे find_ip4_in_cidr4() कहा जाता है . यह कुछ हद तक बिल्ट-इन फ़ंक्शन के समान काम करता है FIND_IN_SET() -- आप इसे एक मान देते हैं और आप इसे एक "सेट" (CIDR युक्ति) देते हैं और यह यह इंगित करने के लिए एक मान देता है कि मान सेट में है या नहीं।

सबसे पहले, क्रिया में फ़ंक्शन का एक उदाहरण:

यदि पता ब्लॉक के अंदर है, तो उपसर्ग की लंबाई लौटाएं। उपसर्ग लंबाई क्यों लौटाएं? गैर-शून्य पूर्णांक "सत्य" हैं, इसलिए हम केवल 1 . वापस कर सकते हैं , लेकिन यदि आप मेल खाने वाले परिणामों को क्रमबद्ध करना चाहते हैं तो एक से अधिक मेल खाने वाले उपसर्गों में से सबसे छोटा या सबसे लंबा पता लगाना चाहते हैं, तो आप ORDER BY फ़ंक्शन का रिटर्न मान।

mysql> SELECT find_ip4_in_cidr4('203.0.113.123','203.0.113.0/24');
+-----------------------------------------------------+
| find_ip4_in_cidr4('203.0.113.123','203.0.113.0/24') |
+-----------------------------------------------------+
|                                                  24 |
+-----------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT find_ip4_in_cidr4('192.168.100.1','192.168.0.0/16');
+-----------------------------------------------------+
| find_ip4_in_cidr4('192.168.100.1','192.168.0.0/16') |
+-----------------------------------------------------+
|                                                  16 |
+-----------------------------------------------------+
1 row in set (0.00 sec)

ब्लॉक में नहीं? वह 0 (गलत) लौटाता है।

mysql> SELECT find_ip4_in_cidr4('192.168.100.1','203.0.113.0/24');
+-----------------------------------------------------+
| find_ip4_in_cidr4('192.168.100.1','203.0.113.0/24') |
+-----------------------------------------------------+
|                                                   0 |
+-----------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT find_ip4_in_cidr4('192.168.100.1','192.168.0.0/24');
+-----------------------------------------------------+
| find_ip4_in_cidr4('192.168.100.1','192.168.0.0/24') |
+-----------------------------------------------------+
|                                                   0 |
+-----------------------------------------------------+
1 row in set (0.00 sec)

सभी-शून्य पते के लिए एक विशेष मामला है, हम -1 लौटाते हैं (अभी भी "सत्य", लेकिन सॉर्ट क्रम को संरक्षित करता है):

mysql> SELECT find_ip4_in_cidr4('192.168.100.1','0.0.0.0/0');
+------------------------------------------------+
| find_ip4_in_cidr4('192.168.100.1','0.0.0.0/0') |
+------------------------------------------------+
|                                             -1 |
+------------------------------------------------+
1 row in set (0.00 sec)

निरर्थक तर्क शून्य लौटते हैं:

mysql> SELECT find_ip4_in_cidr4('234.467.891.0','192.168.0.0/24');
+-----------------------------------------------------+
| find_ip4_in_cidr4('234.467.891.0','192.168.0.0/24') |
+-----------------------------------------------------+
|                                                NULL |
+-----------------------------------------------------+
1 row in set (0.00 sec)

अब, कोडेज़:

DELIMITER $$

DROP FUNCTION IF EXISTS `find_ip4_in_cidr4` $$
CREATE DEFINER=`mezzell`@`%` FUNCTION `find_ip4_in_cidr4`(
  _address VARCHAR(15), 
  _block VARCHAR(18)
) RETURNS TINYINT
DETERMINISTIC /* for a given input, this function always returns the same output */
CONTAINS SQL /* the function does not read from or write to tables */
BEGIN

-- given an IPv4 address and a cidr spec,
-- return -1 for a valid address inside 0.0.0.0/0
-- return prefix length if the address is within the block,
-- return 0 if the address is outside the block,
-- otherwise return null

DECLARE _ip_aton INT UNSIGNED DEFAULT INET_ATON(_address);
DECLARE _cidr_aton INT UNSIGNED DEFAULT INET_ATON(SUBSTRING_INDEX(_block,'/',1));
DECLARE _prefix TINYINT UNSIGNED DEFAULT SUBSTRING_INDEX(_block,'/',-1);
DECLARE _bitmask INT UNSIGNED DEFAULT (0xFFFFFFFF << (32 - _prefix)) & 0xFFFFFFFF;

RETURN CASE /* the first match, not "best" match is used in a CASE expression */
  WHEN _ip_aton IS NULL OR _cidr_aton IS NULL OR /* sanity checks */
       _prefix  IS NULL OR _bitmask IS NULL OR
       _prefix NOT BETWEEN 0 AND 32 OR
       (_prefix = 0 AND _cidr_aton != 0) THEN NULL
  WHEN _cidr_aton = 0 AND _bitmask = 0 THEN -1
  WHEN _ip_aton & _bitmask = _cidr_aton & _bitmask THEN _prefix /* here's the only actual test needed */
  ELSE 0 END;

END $$
DELIMITER ;

एक समस्या जो संग्रहीत कार्यों के लिए विशिष्ट नहीं है, बल्कि अधिकांश RDBMS प्लेटफॉर्म पर अधिकांश कार्यों पर लागू होती है, वह यह है कि जब एक कॉलम का उपयोग WHERE में किसी फ़ंक्शन के तर्क के रूप में किया जाता है। , सर्वर क्वेरी को अनुकूलित करने के लिए किसी अनुक्रमणिका का उपयोग करने के लिए फ़ंक्शन के माध्यम से "पीछे की ओर नहीं देख सकता"।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. क्या मैं MySQL में डिफ़ॉल्ट मान के लिए फ़ंक्शन का उपयोग कर सकता हूं?

  2. mysql में एक साथ अद्वितीय कुंजी बदलें

  3. MySQL समय सीमा से विभाजित

  4. टूटे हुए SQL व्यू को कैसे ठीक करें

  5. हाइबरनेट OneToOne आलसी लोडिंग और कैस्केडिंग