2009-07-05 58 views
4

我們有一個Oracle數據庫,其中包含以十進制整數形式存儲的IP地址 - 當用手操作數據而不是通過Web界面時,這非常痛苦,操作非常方便,因爲網絡人員不斷要求我們做一些奇怪的事情,網絡界面的作者沒有預料到。以十進制形式存儲的IP地址 - PL/SQL以點陣形式顯示

有人能給我提供PL/SQL或其他方法來顯示這些十進制IP作爲點分十進制,即123.123.123.123格式?

I.e.我想能夠運行查詢,例如:

select hostname, inttoip(ip_address) from host; 

和具有inttoip()過程顯示IP_ADDRESS作爲203.30.237.2而不是作爲3407801602.

理想我想它提供了一個過程反函數也是如此,例如

insert into host (hostname,ip_address) values ('some-hostname', iptoint('203.30.237.2')); 

我有perl來做這件事,但是我的PL/SQL/Oracle知識不夠好,無法將它移植到PL/SQL中。


或者的方式來運行Perl作爲類似於Postgres的以下神諭範圍內的程序語言:

CREATE FUNCTION perl_func (integer) RETURNS integer AS $$ 
<some perl> 
$$ LANGUAGE plperl; 

將是巨大的 - 如果可能的話 - 可能甚至更好,因爲我可以用我熟悉的語言在Oracle內部完成大量程序性任務。

+0

裏面有甲骨文JVM。是否存在可以在JVM內部運行的perl版本?如果是這樣你可以使用Perl。例如,可以使用Oracle JVM運行Jython。請閱讀此處:http://forums.oracle.com/forums/thread.jspa?threadID=492882&tstart=15 – tuinstoel 2009-07-05 17:11:41

回答

6

這是你需要的功能:

create or replace 
function inttoip(ip_address integer) return varchar2 
deterministic 
is 
begin 
    return to_char(mod(trunc(ip_address/256/256/256),256)) 
      ||'.'||to_char(mod(trunc(ip_address/256/256),256)) 
      ||'.'||to_char(mod(trunc(ip_address/256),256)) 
      ||'.'||to_char(mod(ip_address,256)); 
end; 

(約製作功能確定性,並使用機上取TO_CHAR評論 - 感謝)。

在Oracle 11g中,你可以做格式化的IP地址上的主機表中的虛擬列:如果需要

alter table host 
add formatted_ip_address varchar2(15) 
generated always as 
(to_char(mod(trunc(ip_address/256/256/256),256)) 
      ||'.'||to_char(mod(trunc(ip_address/256/256),256)) 
      ||'.'||to_char(mod(trunc(ip_address/256),256)) 
      ||'.'||to_char(mod(ip_address,256)) 
) virtual; 

此列然後可以編入索引的查詢。

您的查詢就會變成:

select hostname, formatted_ip_address from host; 
+0

您可以將該函數聲明爲確定性函數。這使得可以在基於函數的索引(fbi)中使用該函數。使用fbi可以解決性能問題。 – tuinstoel 2009-07-05 17:17:32

+0

您甚至可以將MOD(.....)定義爲基表的視圖中的列,從而避免PL/SQL層。 11g可以將它作爲一個虛擬列。 – 2009-07-05 23:13:24

2
CREATE OR REPLACE 
FUNCTION inttoip(ip_address IN INTEGER) RETURN VARCHAR2 IS 
    v8 VARCHAR2(8); 
BEGIN 
    -- 1. convert the integer into hexadecimal representation 
    v8 := TO_CHAR(ip_address, 'FMXXXXXXXX'); 
    -- 2. convert each XX portion back into decimal 
    RETURN to_number(substr(v8,1,2),'XX') 
     || '.' || to_number(substr(v8,3,2),'XX') 
     || '.' || to_number(substr(v8,5,2),'XX') 
     || '.' || to_number(substr(v8,7,2),'XX'); 
END inttoip; 

CREATE OR REPLACE 
FUNCTION iptoint(ip_string IN VARCHAR2) RETURN INTEGER IS 
    d1 INTEGER; 
    d2 INTEGER; 
    d3 INTEGER; 
    q1 VARCHAR2(3); 
    q2 VARCHAR2(3); 
    q3 VARCHAR2(3); 
    q4 VARCHAR2(3); 
    v8 VARCHAR2(8); 
BEGIN 
    -- 1. parse the input, e.g. '203.30.237.2' 
    d1 := INSTR(ip_string,'.');  -- first dot 
    d2 := INSTR(ip_string,'.',1,2); -- second dot 
    d3 := INSTR(ip_string,'.',1,3); -- third dot 
    q1 := SUBSTR(ip_string, 1, d1 - 1);   -- e.g. '203' 
    q2 := SUBSTR(ip_string, d1 + 1, d2 - d1 - 1); -- e.g. '30' 
    q3 := SUBSTR(ip_string, d2 + 1, d3 - d2 - 1); -- e.g. '237' 
    q4 := SUBSTR(ip_string, d3 + 1);    -- e.g. '2' 
    -- 2. convert to a hexadecimal string 
    v8 := LPAD(TO_CHAR(TO_NUMBER(q1),'FMXX'),2,'0') 
    || LPAD(TO_CHAR(TO_NUMBER(q2),'FMXX'),2,'0') 
    || LPAD(TO_CHAR(TO_NUMBER(q3),'FMXX'),2,'0') 
    || LPAD(TO_CHAR(TO_NUMBER(q4),'FMXX'),2,'0'); 
    -- 3. convert to a decimal number 
    RETURN TO_NUMBER(v8, 'FMXXXXXXXX'); 
END iptoint; 
0
-- INET ATON en INET NTOA and helper function GET TOKEN 

     CREATE OR REPLACE function inet_ntoa (ip integer) return varchar2 
    is 
     ip1 integer; 
     ip2 integer; 
     ip3 integer; 
     ip4 integer; 
     ipi integer := ip; 
    begin 
     ip1 := floor(ipi/power(2,24)); 
     ipi := ipi - (ip1*power(2,24)); 
     ip2 := floor(ipi/power(2,16)); 
     ipi := ipi - (ip2*power(2,16)); 
     ip3 := floor(ipi/power(2,8)); 
     ipi := ipi - (ip3*power(2,8)); 
     ip4 := ipi; 
     return ip1||'.'||ip2||'.'||ip3||'.'||ip4; 

    end; 
    / 

CREATE OR REPLACE FUNCTION get_token (the_list VARCHAR2,the_index NUMBER, delim VARCHAR2 := '.') RETURN VARCHAR2 
     IS 
      start_pos INTEGER; 
      end_pos  INTEGER; 
     BEGIN 
      IF the_index = 1 THEN 
       start_pos := 1; 
      ELSE 
       start_pos := INSTR (the_list, delim, 1, the_index - 1); 
       IF start_pos = 0 THEN 
       RETURN NULL; 
       ELSE 
       start_pos := start_pos + LENGTH (delim); 
       END IF; 
      END IF; 
      end_pos := INSTR (the_list, delim, start_pos, 1); 
      IF end_pos = 0 THEN 
       RETURN SUBSTR (the_list, start_pos); 
      ELSE 
       RETURN SUBSTR (the_list, start_pos, end_pos - start_pos); 
      END IF; 
     END get_token; 
     /




    CREATE OR REPLACE function inet_aton (ip varchar2) return integer 
    is 
     invalid_ip_adres exception; 
     pragma exception_init(invalid_ip_adres,-6502); 
     ipi integer; 
    begin 
     ipi := get_token(ip,4) 
      +(get_token(ip,3)*power(2,8)) 
        +(get_token(ip,2)*power(2,16)) 
        +(get_token(ip,1)*power(2,24)); 
     return ipi; 
    exception 
     when invalid_ip_adres 
     then 
      return null; 
    end; 
    /