2009-07-05 8 views
4

IPアドレスを10進数で格納したOracleデータベースがあります。これはWebインタフェースではなく手でデータを操作すると非常に苦痛ですネットワークの人たちが、ウェブインターフェースの作者が予期していない奇妙なことを私たちに依頼しているので、操作は本当に便利です。小数点として格納されたIPアドレス - 点線の四角で表示するPL/SQL

これらの10進数のIPをドット付き小数点(123.123.123.123)の形式で表示する方法はありますか?

I.e.代わりの3407801602.

として理想的には私が提供する手続きを希望

select hostname, inttoip(ip_address) from host; 

と203.30.237.2としてinttoip()手順表示IP_ADDRESSを持っている:私は、次のようなクエリを実行できるようにしたいのですが逆関数も、例えば

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

私はこれを行うにはperlを持っていますが、PL/SQL/Oracleの知識はPL/SQLに移植するには十分ではありません。


また postgresの中で次のように類似のOracleコンテキスト内で手続き型言語としてPerlを実行する方法:

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

は素晴らしいことだ - 可能であれば - おそらく私が慣れ親しんだ言語でOracle内で多くの手続きを行うことができたので、さらに優れていました。

+0

Oracleの内部JVMがあります。 JVMの内部で動作するPerlのバージョンは存在しますか?もしそうなら、あなたはperlを使うことができます。たとえば、Oracle JVMを使用してJythonを実行することが可能です。ここをクリックしてください:http://forums.oracle.com/forums/thread.jspa?threadID=492882&tstart=15 – tuinstoel

答えて

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を使用してについてのコメント - 感謝)。必要に応じて

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; 

この列には、その後のクエリのためにインデックスを作成することができます

は、Oracle 11gでは、あなたは、フォーマットされたIPアドレスホストテーブル上の仮想列作ることができます。

あなたのクエリは次のようになります。

select hostname, formatted_ip_address from host; 
+0

その関数を確定的に宣言することができます。これにより、関数ベースのインデックス(fbi)でその関数を使用することが可能になります。 fbiを使用すると、パフォーマンスの問題を解決できます。 – tuinstoel

+0

MOD(.....)は、PL/SQLレイヤーを避けて、ベース・テーブルのビューの列として定義することもできます。 11gはそれを仮想列として持つことができます。 –

+0

私はそこに自分自身を変換するために明示的な数字を使用していると思います。 –

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; 
    /
+1

私はinet_aton()を探していましたが、ここで私はこの投稿とあなたの機能を見つけています。どうもありがとうございます! P.P.inet_ * deterministicを宣言する必要があります。 –

+0

ようこそ。先端に感謝します。計算だけを含む関数は、決定論的として宣言されるべきです。 –

+0

計算だけを含めることが何を意味するのか分かりません。 「決定論的」は、関数の結果が同じ入力に対して決して変更されないことをOracleに伝えます。ですから、関数のインデックスをinet_ *関数のいずれかに追加したい場合は、それらを宣言しなければなりません(そしてそれらは本質的にすでに決定論的です)。 –

関連する問題