在Oracle中表示IPv4/IPv6地址

pil*_*row 15 oracle ipv4 ipv6

在Oracle中,用于表示网络地址的适当数据类型或技术是什么,哪些地址可能是IPv4或IPv6?

背景:我正在转换一个表记录网络活动,使用PostgreSQL inet数据类型构建,以在同一个表中保存v4和v6地址.

但是,没有行包含v4和v6地址.(也就是说,记录来自机器的v4堆栈或机器的v6堆栈.)

Ala*_*ier 16

在Oracle中,用于表示网络地址的适当数据类型或技术是什么,哪些地址可以是IPv4或IPv6

有两种方法:

  1. 只存储.
  2. 存储传统的表示

仅用于存储.IPV4地址应该是一个整数(32位就足够了).对于IP V6,128位,INTEGER(类似于Number(38))将会这样做.当然,这是存储.该方法认为表示是应用程序的问题.

如果采用相反的策略来存储传统表示,则需要确保IP V4和IPV6地址仅具有一个传统(字符串)表示.它以ipV4而闻名.至于IPV6,还有一种标准格式.

我倾向于第一个策略.在最坏的情况下,您可以采用混合方法(尽管非酸)并且将二进制和ascii表示并排存储到二进制值的"优先级".

但是,没有行包含v4和v6地址.

IPV6格式的IPV4地址的标准表示为:::ffff:192.0.2.128.

我不知道上下文,但我会保留2列,一列用于IPV4,另一列用于不同的ipV6地址.

更新
在@ sleepyMonad的好评之后,我想指出的是,最好使用INTEGER数据类型而不是Number数据类型,它将很好地容纳可用128位整数表示的最高值. 'ff ... ff'(需要39位十进制数字).38是10的最高功率,范围从0到9,可以在128位上编码,但是仍然可以插入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
Run Code Online (Sandbox Code Playgroud)

  • @Alain Pannetier.我尝试了你的代码,你是对的,它有效.describe-functions的输出似乎是错误的.我查询了user_tab_columns,它为我提供了data_precision NULL和INTEGER列,38为NUMBER(38)列.当我有更多时间时,我会进一步调查.我认为你不应该依赖这个没有文档的功能. (3认同)

Bra*_*vic 7

将其存储在RAW中.

RAW是可变长度字节数组,所以....

  • 只需将IPv4视为4个字节的数组
  • 和IPv6作为16个字节的数组

...并将其中一个直接存储在RAW(16)中.


RAW可以被编入索引,可以是PK,UNIQUE或FOREIGN KEY,因此您可以使用VARCHAR2或INT/NUMBER/DECIMAL执行任何通常的操作,但转换和存储开销较少.

为了说明INT相对于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;
Run Code Online (Sandbox Code Playgroud)

结果(在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 
Run Code Online (Sandbox Code Playgroud)