【问题标题】:SQL decode base64 in sql developersql developer中的sql解码base64
【发布时间】:2016-10-23 02:30:34
【问题描述】:

我从 stackoverflow 获得了以下 sql base64 解码器(忘记链接)。我稍微修改了我的要求。当我尝试执行时,解码只是部分工作。我的数据库中每行最多有 10MB 的 base64 编码 clob 数据。

不知道我错过了什么。

create or replace FUNCTION Decode64_CLOB3(IN_CLOB CLOB) RETURN CLOB IS
 clobOriginal     clob;
clobInBase64     clob;
substring        varchar2(2000);
n                pls_integer := 0;
substring_length pls_integer := 2000;

function from_base64(t in varchar2) return varchar2 is
 begin
return     
utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
 end from_base64;

 begin
    select myCLobData into clobInBase64 from myClobTable where ID = 3;
clobInBase64 :=IN_CLOB;
   n := 0;
  clobOriginal := null;

while true loop 

 substring := dbms_lob.substr(clobInBase64,
                          least(substring_length, length(clobInBase64) -   (substring_length * n + 1)));  

  if substring is null then
DBMS_OUTPUT.put_line('this is me 2');
  exit;
end if;  
clobOriginal := clobOriginal || from_base64(substring);  
n := n + 1;  
  end loop;
 return clobOriginal;
 end;

更新2

我做了一些调试,发现问题出在子字符串上。 该子字符串适用于 (2000) 字符的第一个循环。但它无法移动下一个 2000 字符。不确定是什么问题。有人可以建议。

【问题讨论】:

  • 我猜你开始from this answer? “部分工作”是什么意思 - 会发生什么?解码后的值是多少?应该解码为 CLOB 还是 BLOB?
  • @AlexPoole 是的,你说得对。它只打印一行解码值,SQL 开发人员进入挂起状态。我尝试将结果假脱机到一个文件中,它再次只打印 1 行。不知道我错过了什么。我正在将其解码为 CLOB。

标签: sql oracle plsql base64 decoder


【解决方案1】:

您已将调用更改为dbms_lob.substr(),并在此过程中删除了第三个参数,即偏移量。由于您没有提供默认值为 1,因此每次循环时您都会获得相同的值 - 编码字符串中的前 2000 个字符。

好吧,您将获得 2000 的大量调用,然后一旦 n 变得足够大,您将使用您发布的代码获得空值。由于您说它进入“挂起”状态,这表明您正在运行的内容略有不同。

稍作修改后,这似乎可行:

create or replace function decode64_clob3(p_clob_encoded clob)
  return clob
is
  l_clob_decoded clob;
  substring varchar2(2048);
  substring_length pls_integer := 2048;
  n pls_integer := 0;

  function from_base64(t in varchar2) return varchar2
  is
  begin
    return utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(t)));
  end from_base64;

begin
  dbms_lob.createtemporary(l_clob_decoded, false);
  while true
  loop
    substring := dbms_lob.substr(p_clob_encoded, substring_length,
      (substring_length * n) + 1);
    if substring is null then
      exit;
    end if;
    dbms_lob.append(l_clob_decoded, from_base64(substring));
    n := n + 1;
    /* protective check for infinite loop while debugging
    if n > 10000 then
      dbms_output.put_line('n is ' || n);
      exit;
    end if;
    */
  end loop;

  return l_clob_decoded;
end;
/

我稍微改变了 CLOB 处理;连接很好,但这更明确一点。不过,我个人不确定我是否会为嵌套函数而烦恼。而且我不确定least() 计算是否真的添加了任何东西。

但是,如果 base64 编码的值是换行的,那么 ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275ORA-14553: cannot perform a lob write operation inside a query 可能会出错,这通常是这种情况。第一个块解码正常,但下一个块以一个未使用的换行符开始,它把所有东西都扔掉并产生垃圾;最终,垃圾为 null 或导致这些异常之一的其他值。

因此,您需要在通过 CLOB 时以换行长度的倍数跟踪位置;并调整跟踪位置以考虑额外的换行符:

create or replace function decode64_clob3(p_clob_encoded clob)
  return clob
is
  l_clob_decoded clob;
  l_substring varchar2(2048);
  l_substring_length pls_integer := 2048;
  l_pos pls_integer := 1;
begin
  dbms_lob.createtemporary(l_clob_decoded, false);
  while l_pos <= dbms_lob.getlength(p_clob_encoded)
  loop
    l_substring := dbms_lob.substr(p_clob_encoded, l_substring_length, l_pos);
    if l_substring is null then
      exit;
    end if;
    dbms_lob.append(l_clob_decoded,
      utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(l_substring))));

    /* Adjust l_pos to skip over CR/LF chars if base64 is line-wrapped */
    l_pos := l_pos + length(l_substring);
    while dbms_lob.substr(p_clob_encoded, 1, l_pos) in (chr(10), chr(13)) loop
      l_pos := l_pos + 1;
    end loop;
  end loop;

  return l_clob_decoded;
end;
/

或者先去掉任何潜在的换行符/回车符:

create or replace function decode64_clob3(p_clob_encoded clob)
  return clob
is
  l_clob_encoded clob;
  l_clob_decoded clob;
  l_substring varchar2(2048);
  l_substring_length pls_integer := 2048;
  l_pos pls_integer := 1;
begin
  l_clob_encoded := replace(replace(p_clob_encoded, chr(10), null), chr(13), null);
  dbms_lob.createtemporary(l_clob_decoded, false);
  while l_pos <= dbms_lob.getlength(l_clob_encoded)
  loop
    l_substring := dbms_lob.substr(l_clob_encoded, l_substring_length, l_pos);
    if l_substring is null then
      exit;
    end if;
    dbms_lob.append(l_clob_decoded,
      utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(l_substring))));
    l_pos := l_pos + length(l_substring);
  end loop;

  return l_clob_decoded;
end;
/

这适用于包装和未包装的 base64 值。

set serveroutput on
with t (c) as (
  select utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('Hello world'))) from dual
)
select c, decode64_clob3(c)
from t;

C
--------------------------------------------------------------------------------
DECODE64_CLOB3(C)
--------------------------------------------------------------------------------
SGVsbG8gd29ybGQ=                                                                
Hello world

还使用大于substring_length 值的编码值进行了测试。

【讨论】:

  • 感谢您的更新,但执行函数时出现此错误 ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275 ORA-06512:在“SYS.DBMS_LOB”,第 639 行
  • @AKV - 您是否仍在将 CLOB(我的版本中为 l_clob_decoded)初始化为 null,还是在使用 dbms_lob.createtemporary
  • 我尝试将 'dbms_lob.createtemporary' 设置为 true。还尝试将 clob 设置为 null 两种方式我都得到了上述错误。
  • 我可以知道你的测试 clob 数据有多大吗?
  • 现在我得到 RA-14553: cannot perform a lob write operation inside a query ORA-06512: at "SYS.DBMS_LOB", line 639 这个错误。我的 clob 数据最大为 10 MB。
猜你喜欢
  • 1970-01-01
  • 2011-07-02
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 2011-06-05
  • 2012-06-14
  • 2015-11-26
  • 1970-01-01
相关资源
最近更新 更多