2

目前我正在使用OCIEnvCreate()创建一个 OCI 会话句柄来与 Oracle 数据库进行通信。我想明确地使用 UTF8 而不是依赖于已设置的任何客户端语言环境,并且我收集到我需要使用它OCIEnvNlsCreate()来执行此操作。但是有一点我不明白。这是 的签名OCIEnvNlsCreate()

sword OCIEnvNlsCreate   ( OCIEnv        **envhpp,
                          ub4           mode,
                          dvoid         *ctxp,
                          dvoid         *(*malocfp)
                                             (dvoid *ctxp,
                                              size_t size),
                          dvoid         *(*ralocfp)
                                             (dvoid *ctxp,
                                              dvoid *memptr,
                                              size_t newsize),
                          void          (*mfreefp)
                                             (dvoid *ctxp,
                                              dvoid *memptr))
                          size_t        xtramemsz,
                          dvoid         **usrmempp
                          ub2           charset,
                          ub2           ncharset );

注意charsetncharset是整数类型,而不是字符串。所以我猜我需要指定一个 NLS ID?那么这些 NLS ID 在哪里呢?它们不在任何地方的 OCI 标头中 - 我已经非常彻底地 grep 了它们。我知道应该出现的一些字符串是什么NLS_LANG——比如"CL8MACCYRILLIC""TR8PC857"——但它们的 ID 似乎没有在任何地方发布?

我翻遍了 ID 1-999,OCINlsCharSetIdToName()它告诉我 UTF8 是 871,但我对硬编码感到不安,因为 Oracle 决定不记录或公开它?如果我总是使用OCINlsCharSetNameToId( handle, "UTF8" ),我必须先创建一个虚拟会话句柄(使用OCIEnvCreate()or OCIEnvNlsCreate()),调用OCINlsCharSetNameToId(),关闭虚拟会话句柄,然后OCIEnvNlsCreate()使用 NLS ID 再次调用?

这真的是应该工作的方式吗???我一定有这个错误......?

4

1 回答 1

3

在调用 OCIEnvCreate() 之前尝试在 C++ 代码中调用 setenv()。

或查看 Metalink NOTE.93358.1 SCRIPT: Where to Find Specifications of Character Encoding:

在运行下面的查询之前,首先通过引用上面的 Note:67533.1 创建“dectohex”函数。

set pages 1000
col nls_charset_id for 9999
col hex for a10
col value for a20
select nls_charset_id(value) nls_charset_id,
base_convert.dec_to_hex(nls_charset_id(value)) hex, value
from v$nls_valid_values
where parameter = 'CHARACTERSET'
order by nls_charset_id(value);

NLS_CHARSET_ID HEX        VALUE
-------------- ---------- --------------------
1              1          US7ASCII
...


//Note: the characterset constant number for UTF8 = 871 can be retrieved in NOTE.93358.1 SCRIPT: Where to Find Specifications of Character Encoding
ub2 cs = 871, ncs =871;
sword res = OCICALL(OCIEnvNlsCreate(&_handle, oci_mode, 0/*ctxp*/, 0, 0, 0, 0/*xtramem_sz*/, 0/*usrmempp*/, cs, ncs));

恕我直言,硬编码是安全的。同样的值也在 DB 端被硬编码。PS:转换为目标字符集是在数据库客户端执行的。Oracle Instant 客户端库仅支持 US7ASCII 和 AL32UTF8 字符集。

于 2021-09-13T12:00:16.420 回答