使用将在任何数据库上运行的sql在Integer中转换IP地址的函数

时间:2015-05-22 10:37:24

标签: sql oracle postgresql

我写了函数

CREATE FUNCTION ip2int(text) RETURNS bigint AS $$ 
SELECT split_part($1,'.',1)::bigint*16777216 + split_part($1,'.',2)::bigint*65536 +
 split_part($1,'.',3)::bigint*256 + split_part($1,'.',4)::bigint;
$$ LANGUAGE SQL  IMMUTABLE RETURNS NULL ON NULL INPUT;

SELECT ip2int('200.233.1.2');

适用于postgres数据库。 但是当我在Oracle上运行时它给了我以下错误

  

错误(1,21):PLS-00103:遇到符号")"当期待一个   以下内容:in out double double ref char time timestamp interval   date binarynational character nchar

这是什么解决方案? 有没有办法让它与数据库无关?

3 个答案:

答案 0 :(得分:1)

我意识到在PostgreSQL中,将一种比较常用的编程语言称为" plsql"是常见的,但PostgreSQL支持的语言恰当地称为" plpgsql& #34;和PL / SQL和PL / pgSQL是两种相似但不同的语言。此函数的语法不是Oracle定义的有效PL / SQL。 PL / SQL不使用$$来引用例程的文本; text参数是无类型的,PL / SQL中不允许这样做; PL / SQL不支持$ 1,$ 2等参数标记; Oracle中不支持bigint(尽管您可以定义NUMBER的子类型来处理此问题); Oracle不支持::强制转换运算符;没有提供split_part(虽然我想你可以写自己的);并且最后没有使用LANGUAGE SQL IMMUTABLE ...的东西。 Oracle要求函数由语句块(DECLARE...BEGIN...END)组成,而此函数纯粹是SELECT语句;并且函数中的SELECT语句对Oracle无效,因为Oracle需要FROM子句。所以,基本上,这个函数是无效的PL / SQL。您可以将其转换为类似

的内容
CREATE OR REPLACE FUNCTION ip2int(text IN VARCHAR2)
  RETURN NUMBER
AS
  nRetval  NUMBER;
BEGIN
  SELECT TO_NUMBER(REGEXP_SUBSTR(text, '[0-9]', 1, 1)) * 16777216 +
           TO_NUMBER(REGEXP_SUBSTR(text, '[0-9]', 1, 2)) * 65536 +
           TO_NUMBER(REGEXP_SUBSTR(text, '[0-9]', 1, 3)) * 256 +
           TO_NUMBER(REGEXP_SUBSTR(text, '[0-9]', 1, 4))
    INTO nRetval
    FROM DUAL;

  RETURN nRetval;
END IP2INT;

但做出如此激进的改动似乎并不是你想要做的事情。

The PostgreSQL documentation on converting from PL/SQL to PL/pgSQL可能会为您提供有关此问题所涉及的挑战的一些想法。

祝你好运。

答案 1 :(得分:0)

CREATE OR REPLACE FUNCTION split_part(string VARCHAR2, delimiter VARCHAR2, n NUMBER)
    RETURN VARCHAR2
  IS
    v_start NUMBER(5) := 1;
    v_end NUMBER(5);
  BEGIN
    -- Find the position of n-th -1 delimiter
    IF n > 1 THEN
      v_start := INSTR(string, delimiter, 1, n - 1);

       -- Delimiter not found
       IF v_start = 0 THEN
          RETURN NULL;
       END IF;

       v_start := v_start + LENGTH(delimiter);

    END IF;

    -- Find the position of n-th delimiter
    v_end := INSTR(string, delimiter, v_start, 1);

    -- If not found return until the end of string
    IF v_end = 0 THEN
      RETURN SUBSTR(string, v_start);
    END IF;

    RETURN SUBSTR(string, v_start, v_end - v_start);
  END;


CREATE OR REPLACE FUNCTION ip2int(text IN VARCHAR2)
  RETURN NUMBER
AS
  nRetval  NUMBER;
BEGIN
  SELECT TO_NUMBER(split_part(text,'.',1)) * 16777216 +
           TO_NUMBER(split_part(text,'.',2)) * 65536 +
           TO_NUMBER(split_part(text,'.',3)) * 256 +
           TO_NUMBER(split_part(text,'.',4))
    INTO nRetval
    FROM DUAL;

  RETURN nRetval;
END IP2INT;

答案 2 :(得分:0)

create or replace FUNCTION ip_to_number(ip IN VARCHAR2)
  RETURN NUMBER
AS
    a varchar(20 char);
    b varchar(20 char);
    c varchar(20 char);
    d varchar(20 char);
    i integer;
    j integer;
    k integer;
    ip_value integer;
begin
    i := instr(ip, '.');
    j := instr(ip, '.', 1, 2);
    k := instr(ip, '.', 2, 3);
    if (k = 0) then
        raise_application_error(-20101, 'Incorrect IP format (missing at least one dot)');
    end if;
    a := substr(ip, 1, i - 1);
    b := substr(ip, i + 1, j - i - 1);
    c := substr(ip, j + 1, k - j - 1);
    d := substr(ip, k + 1);
    if (a not between 0 and 255) or (b not between 0 and 255) or (c not between 0 and 255) or (d not between 0 and 255) then
        raise_application_error(-20102, 'Incorrect IP format (octet out of bounds)');
    end if;
    ip_value := to_number(a) * 16777216 +  to_number(b) * 65536 +  to_number(c) * 256 + to_number(d);
    RETURN ip_value;
end;