PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8

Posted

技术标签:

【中文标题】PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8【英文标题】:PLSQL decode NVARCHAR2 from BASE64 to UTF-8 【发布时间】:2016-06-19 12:48:13 【问题描述】:

我有一个数据库,目前只存储英文用户名。

我想合并 BASE64UTF-8 以便以其他语言存储以及;我想将它存储在NVARCHAR2 类型的列中。

数据库过程接收BASE64 中的名称,我通过UTL_ENCODE.BASE64_DECODE 对其进行解码并使用UTL_RAW.CAST_TO_VARCHAR2 将字符串转换为VARCHAR2。但我得到的是胡言乱语,而不是真正的词。

例如,我将 'алекс' 作为BASE64 中的名称。我能够对其进行解码,但对VARCHAR2/NVARCHAR2 的强制转换没有返回值:我得到的只是胡言乱语。

我正在使用 NLS_CHARACTERSET WE8ISO8859P1

Oracle 12c 上运行

这是我用来解码的代码:

DECLARE 
  lv_OrgUserName VARCHAR2(2000);
  lv_encodedUserName VARCHAR2(2000);
  lv_UserName    VARCHAR2(2000);
BEGIN 

lv_OrgUserName := 'алекс';
lv_encodedUserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(lv_OrgUserName)));
DBMS_OUTPUT.PUT_LINE (lv_encodedUserName);
lv_UserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW (lv_encodedUserName)));
DBMS_OUTPUT.PUT_LINE (lv_UserName);

END;

我该如何克服这个问题?

【问题讨论】:

我确认您的代码:它适用于“普通字符”,例如 abc,但不适用于您示例中的外来字符。 @J.Chomel,好的,我怎样才能让它为异国情调的人工作? 我今天做了很多研究,但我无法克服它。我在某处读到这可能来自您的客户端,该客户端未正确设置以处理希腊字符。因此,无论您多么努力,DBMS_OUTPUT 都永远无法输出希腊字符。但这不是最终的,因为我不太了解它! 【参考方案1】:

首先,WE8ISO8859P1(西欧 8 位 ISO 8859 第 1 部分,或 - ISO8859 第 1 部分)不支持西里尔字符: 看到这个链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-1 因此,如果您尝试将алекс 之类的字符串存储到VARCHAR2 变量/列中,您将始终得到a???? 作为结果。 可能在数据库安装过程中,有人没有考虑西里尔字符并选择了错误的代码页。 更好的选择是 ISO/IEC 8859-5(第 5 部分),请参阅此链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-5 一种选择是更改此编码 - 但这并不容易,而且超出了这个问题。


您可以做的是在应用程序的所有必须支持西里尔字符的地方严格使用 NVARCHAR2 数据类型而不是 VARCHAR2 数据类型。 尽管您需要注意,但仍然存在一些陷阱:

你不能使用DBMS_OUTPUT包来调试你的代码,因为这个包只支持VARCHAR2数据类型,它不支持NVARCHAR 您必须在所有文字中使用 N'some string' 文字(带有 N 前缀) --> 'алекс' 是 VARCHAR2 数据类型,并且在您的编码中总是自动转换为 'a????',而 n'алекс' 是 NVARCHAR2 数据类型并且不会发生这种转换。

以下代码在 12c 版本上测试,我使用的是 EE8MSWIN1250 代码页(它也不支持西里尔字符):

select * from nls_database_parameters
where parameter like '%CHARACTERSET%';

PARAMETER                VALUE
-----------------------  ------------
NLS_NCHAR_CHARACTERSET   AL16UTF16
NLS_CHARACTERSET         EE8MSWIN1250

请试一试:

CREATE OR REPLACE PACKAGE my_base64 AS
   FUNCTION BASE64_ENCODE( str nvarchar2 ) RETURN varchar2;
   FUNCTION BASE64_DECODE( str varchar2  ) RETURN nvarchar2;
END;
/

CREATE OR REPLACE PACKAGE BODY my_base64 AS

   FUNCTION BASE64_ENCODE( str nvarchar2 ) RETURN varchar2
   IS 
     lv_encodedUserName VARCHAR2(2000);
   BEGIN
    lv_encodedUserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(str)));
    RETURN lv_encodedUserName;
   END;


   FUNCTION BASE64_DECODE( str  varchar2  ) RETURN nvarchar2
   IS
     lv_UserName    nVARCHAR2(2000);
   BEGIN
      lv_UserName := UTL_RAW.CAST_TO_nVARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW (str)));
      RETURN lv_UserName;
   END;

END;
/

几个例子:

select 'aлекс' As A, n'aлекс' As B from dual;

A     B   
----- -----
a???? aлекс

select my_base64.BASE64_ENCODE( n'аaaлекс' ) As aleks from dual;

ALEKS                                                                          
--------------------------------------------------------------------------------
BDAAYQBhBDsENQQ6BEE= 

select my_base64.BASE64_DECODE( 'BDAAYQBhBDsENQQ6BEE=' ) as aleks from dual;

ALEKS                                                                          
--------------------------------------------------------------------------------
аaaлекс   

select my_base64.BASE64_DECODE( my_base64.BASE64_ENCODE( n'аaaлекс' ) ) as Aleks from dual;

ALEKS                                                                          
--------------------------------------------------------------------------------
аaaлекс  

【讨论】:

太棒了。在 Oracle11g 上也一样。

以上是关于PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8的主要内容,如果未能解决你的问题,请参考以下文章

如何将瑞典语字符插入 NVARCHAR2 Oracle 表列类型?

PLSQL PHP:如何将大型 xml 数据从 PLSQL 函数获取到 PHP

PLSQL:将数据从 XML 解析并插入到表中

Oracle数据库中,使用case语句,遇到VARCHAR2与NVARCHAR2问题

将 plsql 变量值从匿名块打印到 Java

将数据从 PLSQL 程序推送到 Java 应用程序