如何使用 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 );
注意charset
和ncharset
是整数类型,不是字符串。所以我猜我需要指定一个 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 字符集。
目前我正在使用 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 );
注意charset
和ncharset
是整数类型,不是字符串。所以我猜我需要指定一个 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 字符集。