sql >> Databasteknik >  >> RDS >> Oracle

Få IP-adressintervall från xxx.xxx.xx.0/16

Det finns inget direkt sätt att få det. Först måste du dela upp IP i 4 oktetter, sedan måste du konvertera från Binary -> Decimal och vice versa.

För en tid sedan skapade jag ett paket för en sådan uppgift. Nedan ser du bara paketets kropp, den bör tillhandahålla allt för att lösa ditt problem.

CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;


CREATE OR REPLACE PACKAGE BODY IP_Utility AS

    BASE_BIN CONSTANT PLS_INTEGER := 2;
    BASE_OCT CONSTANT PLS_INTEGER := 8;
    BASE_DEC CONSTANT PLS_INTEGER := 10;
    BASE_HEX CONSTANT PLS_INTEGER := 16;

    NUMERIC_OVERFLOW EXCEPTION;
    PRAGMA EXCEPTION_INIT(NUMERIC_OVERFLOW, -1426);

/**
* Function translate a array to PL/SQL Table
* @param Sperator String that separates elements, e.g. ';'
* @return Table of elements (NUMBER)
*/
FUNCTION SplitNumber(LIST IN VARCHAR2, Separator IN VARCHAR2) RETURN NUMBER_TABLE_TYPE IS
    OutTable NUMBER_TABLE_TYPE; 
BEGIN    
    IF LIST IS NULL THEN
        RETURN NULL;
    ELSE
        SELECT TRIM(REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL)) 
        BULK COLLECT INTO OutTable
        FROM dual
        CONNECT BY REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL) IS NOT NULL;
    END IF;

    IF OutTable.COUNT > 0 THEN
        RETURN OutTable;
    ELSE
        RETURN NULL;
    END IF;     
END SplitNumber;



/**
* Convert a decimal nubmer into a binary/octal/hex string 
* @param DecN Integer decimal number
* @param Base The binary base (BASE_BIN, BASE_OCT, BASE_HEX)  
* @return The binary/octal/hex string
*/  
FUNCTION Dec2Base(DecN IN INTEGER, Base IN PLS_INTEGER DEFAULT BASE_HEX) RETURN VARCHAR2 DETERMINISTIC IS
    HexString CONSTANT CHAR(16) := '0123456789ABCDEF';
    DecNumber INTEGER := DecN;
    BaseString VARCHAR2(128) := NULL;
BEGIN
    IF DecN IS NULL THEN
        RETURN NULL;
    END IF;
    IF Base > 16 THEN 
        RAISE NUMERIC_OVERFLOW;
    END IF;
    LOOP
        BaseString := SUBSTR(HexString, MOD(DecNumber, Base) + 1, 1 ) || BaseString;
        DecNumber := TRUNC(DecNumber / Base);
        EXIT WHEN DecNumber = 0;
    END LOOP;
    RETURN BaseString;
END Dec2Base;


/**
* Convert a binary/octal/hex number into a decimal value 
* @param BaseString The binary/octal/hex string
* @param Base The binary base (BASE_BIN, BASE_OCT, BASE_HEX)  
* @return The decimal number    
*/
FUNCTION Base2Dec(BaseString IN VARCHAR2, Base IN PLS_INTEGER DEFAULT BASE_HEX) RETURN INTEGER DETERMINISTIC IS
    BaseNumber INTEGER := 0;
    HexString CONSTANT CHAR(16) := '0123456789ABCDEF';
BEGIN
    IF Base > 16 THEN 
        RAISE NUMERIC_OVERFLOW;
    END IF;
    IF BaseString IS NULL THEN
        RETURN NULL;
    END IF;
    FOR i IN 1..LENGTH(BaseString) LOOP
        BaseNumber := BaseNumber * Base + INSTR(HexString, UPPER(SUBSTR(BaseString, i, 1))) - 1;
    END LOOP;
    RETURN BaseNumber;
END Base2Dec;



/**
* Returns SubnetMask of given IP Address
* @param Ip IP-Address with CIDR, e.g. '10.152.10.17/27'
* @return SubnetMask The Subnet Mask in IPv4 Format, e.g. '255.255.255.224'
*/
FUNCTION GetSubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
    SubnetMask VARCHAR2(16);
    MaskBin VARCHAR2(32);
BEGIN
    IF Ip IS NULL OR NOT REGEXP_LIKE(Ip, '/\d+$') THEN
        RETURN NULL;
    END IF;
    FOR i IN 1..REGEXP_REPLACE(Ip, '.+/') LOOP
        MaskBin := MaskBin || '1';
    END LOOP;
    MaskBin := RPAD(MaskBin, 32, '0');
    FOR i IN 1..4 LOOP
        SubnetMask := SubnetMask ||'.'||Base2Dec(SUBSTR(MaskBin, 8*(i-1)+1, 8 ), BASE_BIN);
    END LOOP;
    SubnetMask := SUBSTR(SubnetMask, 2);
    RETURN SubnetMask;  
END GetSubnetMask;



/**
* Returns Subnet and Broadcast-IP of given IP Address  
* @param Ip IP-Address, e.g. 10.152.10.17
* @param SubnetMask The SubnetMask, e.g. 255.255.255.240  
* @param Subnet Subnet-IP: e.g. 10.152.10.16  
* @param BroadcastIp Broadcast-IP: e.g. 10.152.10.31
*/
PROCEDURE GetIpSubnet(Ip IN VARCHAR2, SubnetMask IN VARCHAR2, Subnet OUT VARCHAR2, BroadcastIp OUT VARCHAR2) IS
    SubnetBin VARCHAR2(8);
    BroadcastBin VARCHAR2(8);
    Ip_Array NUMBER_TABLE_TYPE;
    Mask_Array NUMBER_TABLE_TYPE;
BEGIN
    IF SubnetMask IS NULL OR Ip IS NULL THEN
        RETURN;
    END IF;
    Ip_Array := SplitNumber(Ip, '.');
    Mask_Array := SplitNumber(SubnetMask, '.');
    FOR i IN 1..4 LOOP
        SubnetBin := NULL;
        BroadcastBin := NULL;
        FOR m IN 1..8 LOOP
            IF SUBSTR(LPAD(Dec2Base(Ip_Array(i), BASE_BIN), 8, '0'), m, 1) = 1 
                AND SUBSTR(LPAD(Dec2Base(Mask_Array(i), BASE_BIN), 8, '0'), m, 1) = 1 THEN
                SubnetBin := SubnetBin ||'1';
            ELSE
                SubnetBin := SubnetBin ||'0';
            END IF;         
            IF SUBSTR(LPAD(Dec2Base(Mask_Array(i), BASE_BIN), 8, '0'), m, 1) = 1 THEN
                BroadcastBin := SubnetBin;
            ELSE
                BroadcastBin := BroadcastBin ||'1';
            END IF;         
        END LOOP;
        Subnet := Subnet ||'.'||Base2Dec(SubnetBin, BASE_BIN);
        BroadcastIp := BroadcastIp ||'.'||Base2Dec(BroadcastBin, BASE_BIN);
    END LOOP;
    Subnet := SUBSTR(Subnet, 2);
    BroadcastIp := SUBSTR(BroadcastIp, 2);  
END GetIpSubnet;




END IP_Utility;
/

Eller se en avancerad version av detta paket på oracle PL/SQL hur man beräknar intervall ip för IPv6 cidr




  1. Oracle får 1 timme tillbaka datum

  2. Anropar lagrade procedurer från Java

  3. hur anpassar man "visa processlista" i mysql?

  4. Grundläggande om tabelluttryck, del 6 – Rekursiva CTE:er