2011-05-05 26 views
4

我試圖編寫一個函數來從我在這裏和那裏收集到的位中獲取MD5哈希值。我想獲得散列的小寫十六進制表示。我到目前爲止:Oracle中的MD5(DBMS_OBFUSCATION_TOOLKIT.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開發人員顯示dbms_obfuscation_toolkit包定義顯示了這個:

SUBTYPE varchar2_checksum IS VARCHAR2(16); 

輸出有32個字符,所以我必須做一些錯誤。我的問題:

  • RETURN聲明的正確類型是什麼?
  • 我在做不必要的轉換來計算散列嗎?
+0

這是在那裏我希望能夠接受兩個答案的情況之一...... – 2011-06-09 11:39:37

回答

5

這是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> 

當然,我們可以用一個亞型定義過程的參數,但甲骨文會忽視它。這同樣適用於函數的返回類型...

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參數(或者將函數的RETURN變量)。

這是一種冗長的說法,你可以在你的代碼中使用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> 

因此,最好不要使用不恰當的亞型。相反,申報你自己的。

+0

你的解釋不能再清楚不過了,非常感謝你。 – 2011-06-09 11:38:09

10

在這裏你去:

create or replace function getMD5(
    in_string in varchar2) 
return varchar2 
as 
    cln_md5raw raw(2000); 
    out_raw raw(16); 
begin 
    cln_md5raw := utl_raw.cast_to_raw(in_string); 
    dbms_obfuscation_toolkit.md5(input=>cln_md5raw,checksum=>out_raw); 
    -- return hex version (32 length) 
    return rawtohex(out_raw); 
end; 

32長度是因爲它是原始(16)值的十六進制表示。或者,修改上面的內容以輸出原始版本並將原始數據存儲在RAW列中(使用的空間較少,但未來將進行rawtohex和hextoraw轉換,請相信我)。

乾杯

+0

不錯!我終於使用了這種變化。最重要的是,它最終幫助我弄清楚內部工作是如何工作的。我使用的'MD5(INPUT_STRING => CADENA)'實際上返回一個字符串,但它包含'0x5F4D ...'字節而不是文字''5F4D''表示。因此我們使用'RAW'作爲中間格式,所以我們可以使用'RAWTOHEX()'。 (強制自動從RAW轉換爲VARCHAR似乎也可以。) – 2011-06-09 11:30:23