programing

Oracle에서 IPv4/IPv6 주소 표시

starjava 2023. 7. 21. 20:26
반응형

Oracle에서 IPv4/IPv6 주소 표시

Oracle에서 네트워크 주소를 나타내는 데 적합한 데이터 유형 또는 기법은 무엇입니까? IPv4 또는 IPv6 중 어떤 주소가 될 수 있습니까?

배경:Postgre를 사용하여 작성된 네트워크 활동을 기록하는 테이블을 변환하는 중입니다.동일한 테이블에 v4 및 v6 주소를 모두 포함하는 SQL 데이터 유형입니다.

그러나 v4 및 v6 주소를 모두 포함하는 행은 없습니다. 즉, 레코드는 시스템의 v4 스택 또는 시스템의 v6 스택에서 가져온 것입니다.

Oracle에서 네트워크 주소를 나타내는 데 적합한 데이터 유형 또는 기법은 무엇이며, 주소는 IPv4 또는 IPv6일 수 있습니다.

두 가지 접근 방식이 있습니다.

  1. 보관 전용
  2. 전통적인 표현 저장

보관 전용.IPV4 주소는 정수여야 합니다(32비트로 충분).IPv6의 경우 128비트, INTEGER(숫자(38)와 유사)가 좋습니다.물론, 그것은 저장입니다.이러한 접근 방식은 표현이 애플리케이션의 문제라는 관점을 취합니다.

기존 표현을 저장하는 것과 반대되는 전략을 사용하는 경우 IPv4 및 IPV6 주소에 기존(문자열) 표현이 하나만 있는지 확인해야 합니다.ipV4로 잘 알려져 있습니다.IPV6에 대해서는 표준 형식도 있습니다.

제가 선호하는 것은 첫 번째 전략입니다.최악의 경우 하이브리드 접근 방식(비산)을 채택하고 이진 및 ASCII 표현을 이진 값에 "우선 순위"와 함께 나란히 저장할 수 있습니다.

그러나 v4 및 v6 주소를 모두 포함하는 행은 없습니다.

은 다음과 IPV6 "IPV4 "는 다음과 같습니다.::ffff:192.0.2.128.

상황은 잘 모르겠지만 IPV4용과 ipV6 주소용으로 두 개의 열을 예약하고 싶습니다.


@sleepyMonad's의 좋은 의견에 따르면, 숫자 데이터 유형 대신 128비트 정수 'ff...ff'(십진수 39자리 필요)로 표현할 수 있는 가능한 가장 높은 값을 만족스럽게 수용하는 INTERGER 데이터 유형을 사용하는 것이 더 바람직하다는 점을 지적하고 싶습니다.38은 128비트로 인코딩할 수 있는 0에서 9까지의 최대 거듭제곱이지만 2**128 - 1에 대한 최대 부호 없는 값을 삽입할 수 있습니다(예: 340282366920938463463374607431768211455).이 가능성을 설명하기 위한 작은 테스트가 있습니다.

create table test (
  id integer primary key,
  ipv6_address_bin INTEGER );

-- Let's enter 2**128 - 1 in the nueric field
insert into test (id, ipv6_address_bin) values ( 1, to_number ( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX') ) ;

-- retrieve it to make sure it's not "truncated".
select to_char ( ipv6_address_bin, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' ) from test where id = 1 ;
-- yields 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'

select to_char ( ipv6_address_bin ) from test where id = 1 ;
-- yields 340282366920938463463374607431768211455

select LOG(2, ipv6_address_bin) from test where id = 1 ;
-- yields 128

select LOG(10, ipv6_address_bin) from test where id = 1 ;
-- yields > 38

RAW에 저장합니다.

RAW는 가변 길이 바이트 배열이므로...

  • IPv4를 4바이트 배열로 처리합니다.
  • 16바이트 배열의 IPv6

둘 중 하나를 RAW(16)에 직접 저장합니다.


RAW는 PK, 고유 또는 외래 키로 인덱싱할 수 있으므로 VARCHAR2 또는 INT/NUMBER/DECIMAL을 사용하여 일반적으로 수행할 수 있는 모든 작업을 수행할 수 있지만 변환 및 스토리지 오버헤드는 줄어듭니다.

INT over RAW의 스토리지 오버헤드를 설명하려면 다음 예를 고려하십시오.

CREATE TABLE IP_TABLE (
    ID INT PRIMARY KEY,
    IP_RAW RAW(16), 
    IP_INT INT
);

INSERT INTO IP_TABLE (ID, IP_RAW, IP_INT) VALUES (
    1,
    HEXTORAW('FFFFFFFF'),
    TO_NUMBER('FFFFFFFF', 'XXXXXXXX')
);

INSERT INTO IP_TABLE (ID, IP_RAW, IP_INT) VALUES (
    2,
    HEXTORAW('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'),
    TO_NUMBER('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
);

SELECT VSIZE(IP_RAW), VSIZE(IP_INT), IP_TABLE.*  FROM IP_TABLE;

결과(Oracle 10.2에 따라):

table IP_TABLE created.
1 rows inserted.
1 rows inserted.
VSIZE(IP_RAW)          VSIZE(IP_INT)          ID                     IP_RAW                           IP_INT                 
---------------------- ---------------------- ---------------------- -------------------------------- ---------------------- 
4                      6                      1                      FFFFFFFF                         4294967295             
16                     21                     2                      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 340282366920938463463374607431768211455 

@알랭 파네티에(아직 논평할 수 없기 때문에):ANSI INTEGER 데이터 유형은 http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#i54335 에 따라 Oracle의 NUMBER(38)에 매핑됩니다.표 아래에는 NUMBER가 128비트 IPv6 주소로는 충분하지 않은 126비트 이진 정밀도만 제공한다는 정보가 있습니다.최대값은 정상적으로 저장되지만 다음으로 낮은 값으로 반올림되는 주소가 있습니다.

내부 숫자 형식은 ROUND((길이(p)+s)/2)+1(http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#i16209) )입니다.

업데이트: 문제를 다시 처리한 후 IPv6 주소가 포함된 네트워크의 고성능 쿼리를 허용하는 솔루션을 찾았습니다. IPv6 주소와 서브넷 마스크를 RAW(16) 열에 저장하고 UTL_RAW를 사용하여 비교합니다.BIT_AND:

SELECT name, DECODE(UTL_RAW.BIT_AND('20010DB8000000000000000000000001', ipv6_mask), ipv6_net, 1, 0)
FROM ip_net
WHERE ipv6_net IS NOT NULL;

사용자 지정 오라클 개체를 사용할 수도 있습니다.

SQL>set SERVEROUTPUT on
SQL>drop table test;

Table dropped.

SQL>drop type body inaddr;

Type body dropped.

SQL>drop type inaddr;

Type dropped.

SQL>create type inaddr as object
  2  ( /* TODO enter attribute and method declarations here */
  3  A number(5),
  4  B number(5),
  5  C number(5),
  6  D number(5),
  7  E number(5),
  8  F number(5),
  9  G number(5),
 10  H NUMBER(5),
 11  MAP MEMBER FUNCTION display RETURN VARCHAR2,
 12  MEMBER FUNCTION toString( SELF IN INADDR , CONTRACT BOOLEAN DEFAULT TRUE) RETURN VARCHAR2,
 13  CONSTRUCTOR FUNCTION INADDR(SELF IN OUT NOCOPY INADDR, INADDRASSTRING VARCHAR2)  RETURN SELF AS RESULT
 14  
 15  ) NOT FINAL;
 16  /

SP2-0816: Type created with compilation warnings

SQL>
SQL>
SQL>CREATE TYPE BODY INADDR AS
  2  
  3  MAP MEMBER FUNCTION display RETURN VARCHAR2
  4  IS BEGIN
  5  return tostring(FALSE);
  6  END;
  7  
  8  
  9  MEMBER FUNCTION TOSTRING( SELF IN  INADDR , CONTRACT BOOLEAN DEFAULT TRUE) RETURN VARCHAR2 IS
 10  IP4 VARCHAR2(6) := 'FM990';
 11  ip6 varchar2(6) := 'FM0XXX';
 12    BEGIN
 13  IF CONTRACT THEN
 14    ip6 := 'FMXXXX';
 15  end if;
 16  
 17  IF CONTRACT AND A =0 AND B=0 AND C = 0 AND D=0 AND E =0 AND F = 65535 THEN --ipv4
 18      RETURN  '::FFFF:'||TO_CHAR(TRUNC(G/256),'FM990.')||TO_CHAR(MOD(G,256),'FM990.')||TO_CHAR(TRUNC(H/256),'FM990.')||TO_CHAR(MOD(H,256),'FM990');
 19  ELSE
 20      RETURN
 21  TO_CHAR(A,ip6)||':'||
 22  TO_CHAR(B,IP6)||':'||
 23  TO_CHAR(C,ip6)||':'||
 24  TO_CHAR(D,ip6)||':'||
 25  TO_CHAR(E,ip6)||':'||
 26  TO_CHAR(F,ip6)||':'||
 27  TO_CHAR(G,ip6)||':'||
 28  TO_CHAR(H,ip6);
 29  end if;
 30    end;
 31  
 32      CONSTRUCTOR FUNCTION inaddr(SELF IN OUT NOCOPY inaddr, inaddrasstring VARCHAR2)
 33                                 RETURN SELF AS RESULT IS
 34      begin
 35          if instr(inaddrasstring,'.') > 0 then
 36            --ip4
 37  null;
 38              a := 0;
 39              B := 0;
 40              C := 0;
 41              D := 0;
 42              E := 0;
 43              F := TO_NUMBER('FFFF', 'XXXX');
 44              G := TO_NUMBER(TO_CHAR(TO_NUMBER(REGEXP_SUBSTR(INADDRASSTRING,'([0-9]{1,3}).',1,1,'i',1),'999'),'FM0X')
 45  ||TO_CHAR(TO_NUMBER(REGEXP_SUBSTR(INADDRASSTRING,'([0-9]{1,3}).',1,2,'i',1),'999'),'FM0X')
 46  ,'XXXX');
 47              h := TO_NUMBER(TO_CHAR(TO_NUMBER(REGEXP_SUBSTR(INADDRASSTRING,'([0-9]{1,3}).',1,3,'i',1),'999'),'FM0X')
 48  ||TO_CHAR(TO_NUMBER(REGEXP_SUBSTR(INADDRASSTRING,'([0-9]{1,3})',1,4,'i',1),'999'),'FM0X')
 49  ,'XXXX');
 50  
 51          ELSIF instr(inaddrasstring,':') > 0 then
 52              --ip6
 53              a := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,1,'i',1),'XXXX');
 54              b := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,2,'i',1),'XXXX');
 55              c := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,3,'i',1),'XXXX');
 56              d := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,4,'i',1),'XXXX');
 57              E := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,5,'i',1),'XXXX');
 58              f := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,6,'i',1),'XXXX');
 59              g := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,7,'i',1),'XXXX');
 60              H := TO_NUMBER(REGEXP_SUBSTR(inaddrasstring,'([0-9a-fA-F]{1,4})',1,8,'i',1),'XXXX');
 61          end if;
 62  
 63          RETURN;
 64      END;
 65  end;
 66  /

Type body created.

SQL>
SQL>create table test
  2  (id integer primary key,
  3  address inaddr);

Table created.

SQL>
SQL>select * from test;

no rows selected

SQL>
SQL>
SQL>insert into test values (1, INADDR('fe80:0000:0000:0000:0202:b3ff:fe1e:8329') );

1 row created.

SQL>INSERT INTO TEST VALUES (2, INADDR('192.0.2.128') );

1 row created.

SQL>insert into test values (3, INADDR('20.0.20.1') );

1 row created.

SQL>insert into test values (4, INADDR('fe80:0001:0002:0003:0202:b3ff:fe1e:8329') );

1 row created.

SQL>insert into test values (5, INADDR('fe80:0003:0002:0003:0202:b3ff:fe1e:8329') );

1 row created.

SQL>INSERT INTO TEST VALUES (6, INADDR('fe80:0003:0001:0003:0202:b3ff:fe1e:8329') );

1 row created.

SQL>INSERT INTO TEST VALUES (7, INADDR('fe80:0003:0001:0003:0202:b3ff:fe1e:8328') );

1 row created.

SQL>INSERT INTO TEST VALUES (8, INADDR('dead:beef:f00d:cafe:dea1:aced:b00b:1234') );

1 row created.

SQL>
SQL>COLUMN INET_ADDRESS_SHORT FORMAT A40
SQL>column inet_address_full format a40
SQL>
SQL>select t.address.toString() inet_address_short, t.address.display( ) inet_address_full
  2  from test T
  3  order by t.address ;

INET_ADDRESS_SHORT                       INET_ADDRESS_FULL
---------------------------------------- ----------------------------------------
::FFFF:20.0.20.1                         0000:0000:0000:0000:0000:FFFF:1400:1401
::FFFF:192.0.2.128                       0000:0000:0000:0000:0000:FFFF:C000:0280
DEAD:BEEF:F00D:CAFE:DEA1:ACED:B00B:1234  DEAD:BEEF:F00D:CAFE:DEA1:ACED:B00B:1234
FE80:0:0:0:202:B3FF:FE1E:8329            FE80:0000:0000:0000:0202:B3FF:FE1E:8329
FE80:1:2:3:202:B3FF:FE1E:8329            FE80:0001:0002:0003:0202:B3FF:FE1E:8329
FE80:3:1:3:202:B3FF:FE1E:8328            FE80:0003:0001:0003:0202:B3FF:FE1E:8328
FE80:3:1:3:202:B3FF:FE1E:8329            FE80:0003:0001:0003:0202:B3FF:FE1E:8329
FE80:3:2:3:202:B3FF:FE1E:8329            FE80:0003:0002:0003:0202:B3FF:FE1E:8329

8 rows selected.

SQL>spool off

나는 방금 이것을 지난 한 시간 동안 (그리고 동시에 나 자신에게 사물을 가르쳤기 때문에) 그것이 개선될 수 있다고 확신합니다. 만약 내가 업데이트를 한다면 나는 그것들을 여기에 다시 게시할 것입니다.

IP 주소를 SYS_CONTEXT('USERNV', 'IP_ADDRESS')에서 반환하는 문자열 형식으로 저장하고 싶습니다.

11g에서 SYS_CONTEXT와 관련하여 기본 반환 값 길이는 256바이트로만 설명되며 반환 값 크기는 정확하게 설명되지 않습니다.IP_ADDRESS' 컨텍스트입니다.

Oracle DatabaseIPv6 방향 설명서에 설명되어 있습니다.

Oracle Database 11g 릴리스 2는 RFC2732에서 지정한 표준 IPv6 주소 표기법을 지원합니다.128비트 IP 주소는 일반적으로 ":" 기호를 그룹 구분 기호로 사용하여 4개의 16진수로 구성된 8개 그룹으로 표시됩니다.각 그룹의 선행 0이 제거됩니다.예를 들어 1080:0:0:0:8:800:200C:417A는 올바른 IPv6 주소입니다.하나 이상의 연속 0 필드는 선택적으로 "::" 구분 기호로 압축할 수 있습니다.예를 들어 1080::8:800:200C:417A입니다.

이 노트에서 IP_ADDRESS varchar2(39) 열을 만들어 이 그룹 사이에 8개의 그룹을 4자리 숫자로 저장하고 7개의 구분 기호를 사용할 수 있도록 하고 싶습니다.

Oracle 문서에는 INTEGER가 NUMBER(38)의 별칭이라고 명시되어 있지만, 위의 단락에 다음과 같이 명시되어 있기 때문에 아마도 오타일 것입니다.

NUMBER(p,s) 여기서 p는 정밀도...Oracle은 소수점 위치에 따라 소수점 39자리 또는 40자리에 해당하는 최대 20개의 base-100자리의 정밀도를 가진 숫자의 휴대성을 보장합니다.

따라서 NUMBER는 39~40자리의 숫자를 저장할 수 있으며, INTERGER는 NUMBER(38) 대신 NUMBER(최대 정밀도)의 별칭일 가능성이 높습니다.제공된 예제가 작동하는 이유가 있습니다(INTEGER를 NUMBER로 변경하면 작동).

가능성은 다음과 같습니다.

  • 문자열로 저장합니다.VARCHAR2(계속)1080::8:800:200c:417a)
  • 숫자 값으로 저장
    • NUMBER자료형
    • INTEGER자료형
  • 다음으로 저장RAW가치
    • 하나의 RAW 값, 즉.RAW(4)또는RAW(16)각각 IPv4 또는 IPv6의 경우
    • 4 xRAW(1)또는 8xRAW(2)각각 IPv4 또는 IPv6의 경우

를 사용하는 것이 좋습니다.RAW가치들 왜냐하면

  • 문자열을 사용하는 경우 다양한 형식의 IPv6을 고려해야 합니다.

    1080::8:800:200C:417A
    1080::8:800:200c:417a
    1080::8:800:32.12.65.122
    1080:0:0:0:8:800:200C:417A
    1080:0:0:0:0008:0800:200C:417A
    1080:0000:0000:0000:0008:0800:200C:417A
    

    모두 동일한 IPv6 IP-Address의 법적 표현입니다.응용프로그램이 올바른 사용을 위해 공통 형식을 적용해야 합니다(예:WHERE조건.

  • NUMBER/INTEGER값은 사람이 읽을 수 있는 형식으로 변환하지 않으면 의미가 없습니다.사용할 수 없습니다.INTEGERPL/SQL의 데이터 유형

    i INTEGER := 2**128-1; -- i.e. ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    
    -> ORA-06502: PL/SQL: numeric or value error: number precision too large. 
    
  • 서브넷화 작업을 해야 하는 경우 BITAND 기능을 사용할 수 없습니다. 또한 2^127까지의 숫자만 지원합니다.

  • UTL_RAW 함수를 사용할 수 있습니다.UTL_RAW.BIT_AND,UTL_RAW.BIT_COMPLEMENT,UTL_RAW.BIT_OR서브넷 작업에 사용됩니다.

  • 정말 많은 양의 데이터를 처리해야 하는 경우(수십억 개의 행을 말하는 것입니다), IP-Address를 여러 RAW 값(예: 4x)으로 분할하는 것이 유리할 수 있습니다.RAW(1)또는 8xRAW(2)이러한 열은 비트맵 인덱스에 대해 미리 지정되므로 디스크 공간을 많이 절약하고 성능을 향상시킬 수 있습니다.

언급URL : https://stackoverflow.com/questions/4950394/representing-ipv4-ipv6-addresses-in-oracle

반응형