5

我们有一个旧客户端与旧服务器应用程序交谈。在土耳其,它将文本作为 windows-1254 发送。我们将其存储并寄回。

数据库中的一行名称为“İ”,它是大写字母 I,顶部有一个点。在 windows-1254 中,这是一个 0xdd 字符,在 UTF-8 中,是 0xc4b0。

如果我查看数据库,我会看到:

SQL> select dump(name, 16) from thing where other thing;

DUMP(NAME,16)
--------------------------------------------------------------------------------
Typ=1 Len=2: c3,9d

诡异的。正如有人在另一个问题中指出的那样,虽然......

“İ”字符在 windows-1254 中是 0xdd。事实证明,windows-1252 中的 0xdd 是“Ý”字符,在 UTF-8 中是 0xc39d。因此,我们看到的东西被倾倒了。

我们认为我们想要做的是这样,但它显然不起作用:

SQL> update thing set name = UTL_RAW.CAST_TO_VARCHAR2(UTL_RAW.CONVERT(HEXTORAW('dd'), 'CP1254', 'UTF8')) where otherthing;
update thing set name = UTL_RAW.CAST_TO_VARCHAR2(UTL_RAW.CONVERT(HEXTORAW('dd'), 'CP1254', 'UTF8')) where otherthing
                                                        *
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.UTL_RAW", line 327

嗯?

许多文档讨论了 UTL_RAW.CONVERT 并且没有人展示它实际使用的示例。这是为什么?是否有允许的 NLS 字符集名称列表?我找不到一个。有什么建议么?我可以找到 java 知道的所有编码的列表,但我找不到 Oracle 的这个列表。

我有一个 Java 应用程序,我用它来编写必须由旧版软件读取的数据。该应用程序接收 UTF-8。我可以成功地将其转换为 windows-1254 字节。我可以将它们翻译成 windows-1252。如果然后我将它们转换为 UTF-8,我可以将其写入数据库:

SQL> update this set name = UTL_RAW.CAST_TO_VARCHAR2(hextoraw('c39d')) where otherthing;

1 row updated.

SQL> select dump(name, 16) from thing where otherthing;

DUMP(NAME,16)
--------------------------------------------------------------------------------
Typ=1 Len=2: c3,9d

客户端将此行显示为“İ”。但是,你知道,哇。这似乎很荒谬。但如果这是可行的,那可能就是必须发生的事情......

4

1 回答 1

4

文档中没有解释的是,根据 UTL_RAW,一个字符集由 3 个东西组成;NLS_LANGUAGE、NLS_TERRITORY 和字符集本身。要查看您可以查询的有效值列表V$NLS_VALID_VALUES文档中还提供了语言和地区的完整列表。

这引发了您的第一个问题。根据 Oracle Win-1254不是CP1254 而是 TR8MSWIN1254。同样,虽然存在 UTF8 字符集,但我怀疑您的数据库是使用 AL32UTF8 设置的。您可以通过查询进行仔细检查NLS_DATABASE_PARAMETERS

因此,如果这是土耳其语,而您在土耳其,我们假设您的语言和领土就是这样TURKISH_TURKEY

现在将其添加到字符集会返回您想要的内容:

select utl_raw.convert( hextoraw('dd')
                      , 'TURKISH_TURKEY.AL32UTF8'
                      , 'TURKISH_TURKEY.TR8MSWIN1254'
                      ) as raw_char
  from dual;

RAW_CHAR
-----------------------------------------------------

C4B0

正如您已经注意到 0xc4b0 是 İ 在 UTF-8 中的表示,因此您可以UTL_RAW.CAST_TO_VARCHAR2按预期使用1

select utl_raw.cast_to_varchar2(
           utl_raw.convert( hextoraw('dd')
                          , 'TURKISH_TURKEY.AL32UTF8'
                          , 'TURKISH_TURKEY.TR8MSWIN1254'
                            )) as new_char
  from dual;

1.我没有可以代表这个字符的基于文本的Oracle客户端;对不起!

于 2013-09-10T07:31:17.203 回答