从oracle varchar2显示字符串的十六进制值?

时间:2013-09-09 15:39:37

标签: oracle unicode utf-8 turkish ojdbc

我们遇到的问题是文本以某种不同的方式编码,但保存在表格的单个列中。很长的故事。在MySQL上,我可以“从表格中选择十六进制(str)”,我看到字符串的字节完全按照我设置的那样。

在Oracle上,我有一个以土耳其字符İ开头的字符串,它是Unicode字符0x0130“带有上面点的拉丁文大写字母”。这是我的Unicode 2.0版书的印刷版。在UTF-8中,该字符为0xc4b0。

我们需要支持非常旧的客户端应用。他们会在“windows-1254”中将此文本发送给我们。我们过去只是闭上眼睛,存放它,然后再将其交还。现在我们需要Unicode,或者被赋予Unicode。

所以我有:

SQL> select id, name from table where that thing;

ID     NAME
------ ------------------------
746    Ý

这是有道理的,因为“İ”在Windows-1254中是0xdd而wondows-1252中的0xdd是“Ý”。我的终端大概设置为通常的windows-1252。

可是:

SQL> select id, rawtohex(name) from table where that thing;

ID     RAWTOHEX(NAME)
------ ------------------------
746    C39D

似乎没有相当于MySQL中的十六进制(名称)功能。但我必须缺少一些东西。我在这里缺少什么?

我的java代码必须使用我提供的utf8并保存utf8副本和windows-1252副本。 java代码给了我:

bytes (utf8):  c4 b0
bytes (1254):  dd

然而,当我保存它时,客户端没有得到正确的字符。当我试图查看Oracle实际存储的内容时,我会看到上面看到的垃圾。我有没有想法来自C39D的来源。有什么建议吗?

我们在所有应用程序中都内置了ojdbc14.jar,并且我们正在连接到一个数据库,该数据库表示它是“Oracle Database 11g企业版版本11.2.0.2.0 - 64位生产”。

2 个答案:

答案 0 :(得分:19)

使用dump功能查看Oracle如何在内部存储数据。

您似乎对Oracle如何处理VARCHAR2字符设置转换产生了误解:您无法影响Oracle如何存储其数据物理。 (如果您还没有,请阅读:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets)。

您的客户端仅以二进制方式与Oracle通信。事实上,所有系统仅以二进制形式交换信息。为了相互理解,两个系统都必须知道正在使用的语言(字符集)。

在您的情况下,我们可以重建发生的事情:

  1. 您的客户端将字节dd发送给Oracle并说它是windows-1252(而不是1254)
  2. Oracle查找其字符集表,发现此数据已转换为此字符集中的符号Ý
  3. Oracle 逻辑将此信息存储在其表中。
  4. 由于Oracle已在UTF-8中设置,因此会将此数据转换为UTF-8的{​​{1}}二进制代表:

    Ý
  5. Oracle内部存储SQL> SELECT rawtohex('Ý') FROM dual; RAWTOHEX('Ý') -------------- C39D

  6. 正如您所看到的,问题来自第一步:存在设置问题。只要你不解决这个问题,系统将无法成功对话。

    使用C39D时转换为自动,因为此数据类型是逻辑文本符号接口(您无法控制强制存储的实际二进制数据)。

答案 1 :(得分:5)

我开始使用UTF-8中的字节。

String strFromUTF8 = new String(bytes, "UTF8");
byte[] strInOldStyle = strFromUTF8.getBytes("Cp1254");

使用MySQL,我完成了。我获取这些字节,将它们转换为十六进制字符串并使用unhex(hexStr)进行更新。这允许我将遗留字节放入varchar列。

使用Oracle,我必须这样做:

String again = new String(strInOldStyle, "Cp1254");
byte[] nextOldBytes = again.getBytes("UTF8");

现在,我可以进行更新并使用以下命令将字节输入varchar2列:

update table set colName = UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('hexStr')) where ...

奇怪,不是吗?我相信我已经使它变得比它需要的更复杂。

我们看到的是这个,

"İ" in UTF-8 == 0xc4d0
"İ" in Cp1254 == 0xdd == "Ý" in Cp1252
"Ý" in UTF-8 == 0xc3d9

所以,如果我收到字符串“İ”并执行:

update table set name = UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('C3D9')) where ...

然后我们的遗留客户给了我们一个“İ”。是的。它有效。