在Oracle中,表示网络地址的适当数据类型或技术是什么,哪些地址可以是IPv4或IPv6?
背景:我正在转换一个记录网络活动的表,该表使用PostgreSQL inet data type构建,以便在同一个表中同时保存v4和v6地址。
但是,没有行同时包含v4和v6地址。(也就是说,记录要么来自计算机的v4堆栈,要么来自计算机的v6堆栈。)
发布于 2012-02-03 11:11:49
将其存储在RAW中。
RAW是可变长度字节数组,因此....
...and直接在RAW(16)中存储它们中的任何一个。
RAW可以被编入索引,可以是PK、唯一键或外键,因此您可以使用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;结果(在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 发布于 2011-10-20 20:32:11
@Alain Pannetier (因为我还不能评论):根据http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements001.htm#i54335,ANSI整数数据类型映射到Oracle中的NUMBER(38)。在下面的表格中,你会发现这个数字只提供了126位的二进制精度,这对于一个128位的IPv6地址来说是不够的。最大值可能存储得很好,但会有四舍五入到下一个较低值的地址。
内部数字格式为ROUND((length(p)+s)/2))+1 (http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#i16209)。
更新:在再次解决了这个问题之后,我现在找到了一个可以对包含IPv6地址的网络进行高性能查询的解决方案:将IPv6地址和子网掩码存储在原始(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;发布于 2012-05-30 12:02:02
您也可以使用自定义的oracle对象。
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我只是在最后一个小时内把这些东西放在一起(同时还自学了一些对象),所以我相信它是可以改进的。如果我做了更新,我会在这里重新发布
https://stackoverflow.com/questions/4950394
复制相似问题