PLSQL将NVARCHAR2从BASE64解码为UTF-8

时间:2016-06-19 12:48:13

标签: utf-8 plsql oracle12c

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

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

数据库程序在BASE64中收到名称,我正在通过UTL_ENCODE.BASE64_DECODE&使用VARCHAR2将字符串转换为UTL_RAW.CAST_TO_VARCHAR2。但是我得到了胡言乱语而不是实际的话。

例如,我将'алекс'作为BASE64中的名称。我能够解码它,但是VARCHAR2/NVARCHAR2的强制转换不会返回值:我只是乱码。

我使用 Oracle 12c

运行NLS_CHARACTERSET WE8ISO8859P1

以下是我用来解码的代码:

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;

我怎样才能克服这个?

1 个答案:

答案 0 :(得分:2)

首先,WE8ISO8859P1(西欧8位ISO 8859第1部分,或 - ISO8859第1部分)不支持cyryllic字符:
请看这个链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-1

因此,如果您尝试将алекс这样的字符串存储到 VARCHAR2 变量/列中,您将始终获得a????作为结果。

可能在数据库安装过程中,有人没有考虑过cyryllic字符并且选择了错误的代码页 更好的选择是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лекс