我正在尝试编写一个函数来从我在这里和那里收集的位获得MD5哈希值.我想获得哈希的小写十六进制表示.到目前为止我有这个:
CREATE OR REPLACE FUNCTION MD5 ( CADENA IN VARCHAR2 ) RETURN DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM AS BEGIN RETURN LOWER( RAWTOHEX( UTL_RAW.CAST_TO_RAW( DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING => CADENA) ) ) ); END;
我不确定函数的返回类型. DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM看起来是合适的选择,据我所知它可以按预期工作,但sql Developer显示的dbms_obfuscation_toolkit的包定义显示:
SUBTYPE varchar2_checksum IS VARCHAR2(16);
输出有32个字符,所以我一定做错了.我的问题:
> RETURN语句的正确类型是什么?
>我是否进行了不必要的转换来计算哈希值?
解决方法
Oracle PL / sql的一个特点是存储过程参数和函数返回类型不受限制.也就是说,我们不能有这样的签名过程:
sql> create or replace procedure my_proc (p1 in varchar2(30)) 2 is 3 begin 4 null; 5 end; 6 / Warning: Procedure created with compilation errors. sql> show error Errors for PROCEDURE MY_PROC: LINE/COL ERROR -------- ----------------------------------------------------------------- 1/34 PLS-00103: Encountered the symbol "(" when expecting one of the following: := . ),@ % default character The symbol ":=" was substituted for "(" to continue. sql> create or replace procedure my_proc (p1 in varchar2) 2 is 3 begin 4 null; 5 end; 6 / Procedure created. sql>
当然我们可以使用SUBTYPE定义过程的参数,但Oracle会忽略它.函数返回类型也一样……
sql> create or replace package my_subtypes as 2 subtype ltd_string is varchar2(30); 3 end; 4 / Package created. sql> create or replace function my_func return my_subtypes.ltd_string 2 is 3 begin 4 return lpad('a',4000,'a'); 5 end; 6 / Function created. sql> select length(my_func) from dual 2 / LENGTH(MY_FUNC) --------------- 4000 sql>
限制参数和返回类型的唯一方法是使用存储过程中的子类型声明变量.使用包中的变量,并将它们分配给OUT参数(或为函数返回变量).
这是一种冗长的说法,您可以在代码中使用DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM,确信它不会阻止您的函数返回32个字符.
但是,它会使查找SUBTYPE声明的开发人员感到困惑.在最糟糕的情况下,这些人将使用子类型声明他们自己的工作变量,具有以下悲剧结果:
sql> declare 2 v my_subtypes.ltd_string; 3 begin 4 v := my_func; 5 end; 6 / declare * ERROR at line 1: ORA-06502: PL/sql: numeric or value error: character string buffer too small ORA-06512: at line 4 sql>
因此,最好不要使用不合适的子类型.而是声明自己的.