如何使用 OCIEnvNlsCreate() 始终以 UTF8 编码获取 CHAR 和 NCHAR 数据?

How do I use OCIEnvNlsCreate() to always get CHAR and NCHAR data back in UTF8 encoding?

目前我正在使用 OCIEnvCreate() 创建一个 OCI session 句柄来与 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 headers 的任何地方——我已经非常彻底地 grep 了它们。我知道应该出现在 NLS_LANG 中的一些字符串是什么——像 "CL8MACCYRILLIC""TR8PC857" 这样的东西——但是它们的 ID 似乎没有在任何地方发布?

我用 OCINlsCharSetIdToName() 搜索了 ID 1-999,它告诉我 UTF8 是 871,但我对 hard-coding 有一种不安的感觉,因为 Oracle 决定不记录这个或做到 public?如果我总是使用 OCINlsCharSetNameToId( handle, "UTF8" ),我必须首先创建一个虚拟 session 句柄(使用 OCIEnvCreate()OCIEnvNlsCreate()),调用 OCINlsCharSetNameToId(),关闭虚拟 session 句柄,然后用 NLS ID 再次调用 OCIEnvNlsCreate()?

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

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

或检查 Metalink NOTE.93358.1 脚本:在哪里可以找到字符编码规范:

在 运行 下面的查询之前,首先通过引用上面的 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));

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