现在,在与 IBM 支持人员进行了长时间且不紧不慢的交谈后,我可以看到我离最初想法的解决方案还有多远。目的是开发 UDF,它将从表中的位数据列的 char 中获取二进制文本,并以 unicode 形式返回文本。问题是我正在使用的表包含从使用不同 CCSID 的不同县累积的 EBCDIC 文本。不同的行可以包含使用不同 CCSID 编码的文本。这就是为什么我需要 CCSID 的第二个整数参数。
-
函数的正确定义应该是
CREATE FUNCTION US15030.BIN2TEXT (VARCHAR(2023) FOR BIT DATA CCSID UNICODE, INTEGER)
返回 VARGRAPHIC(2023) CCSID UNICODE
在前两行。
这听起来有点奇怪。为什么我应该为包含绝对不在 UNICODE 中的二进制数据的参数分配 CCSID UNICODE?我不希望对输入进行任何转换。但这就是 DB2 的设计方式。它要求在同一个 CCSID 中声明所有字符参数。否则拒绝接受申报。事实上,它没有任何害处。 CHAR BIT DATA 不进行任何转换。
根据 IBM 支持人员的建议,我不得不将输出参数从 VARCHAR 更改为 VARGRAPHIC。
-
我的问题本身包含另一个错误。我希望函数以 UTF-8 格式返回文本。那是个坏主意。带有 C 的 DB2 接口只能使用 UTF-16 unicode。 DB2 从 UDF 中获取 UTF-16 格式的数据,如果将结果插入 unicode 表的文本列,它会自动转换为 UTF-8。
-
没有使用 C 语言进行外部 UDF 开发的经验,我决定从 IBM 提供的一些工作示例开始。我找到了一个,但仅适用于 EBCDIC 数据。我自己的一个基于样本的工作与返回的 EBCDIC VARCHAR 配合良好。
DDL 定义的第一行如下:
CREATE FUNCTION US15030.BIN2TEXT (VARCHAR(1024) FOR BIT DATA, INTEGER )
RETURNS VARCHAR(1024) FOR MIXED DATA CCSID EBCDIC
C 代码中的参数如下:
void SIWBI2TX /* main routine */
( char *inString, /* in: string to convert */
int *inCCSID, /* in: CCSID of string to conv*/
char *outString, /* out: converted string */
short int *ninString, /* in: indic for string to co */
short int *nCCSID , /* in: indic for inCCSID */
short int *noutString, /* out: indic for outString */
char *sqlstate, /* out: SQLSTATE */
char *fnName, /* in: family name of function*/
char *specificName, /* in: specific name of func */
char *message /* out: diagnostic message */
);
为了检查我是否可以正确地传入和传出参数,我只是返回以输出我在输入时以十六进制形式提供的字符串。对我来说最简单的字符串是 €,即 utf-16 中的 20AC 或 UTF-8 中的 E282AC。
我的测试代码以两种形式接收并返回它,没有失真,但是 DB2 没有将它显示为文本,而输出的十六进制看起来与输入的相同。
当我按照上述第 1 项更改 DDL 时,我的 C 代码停止工作。
解决方案是将输入和输出参数类型更改为:
typedef unsigned short sqldbchar;
struct VARGRAPH {
short len;
sqldbchar data[2023];
};
struct VARCHAR {
short len;
char data[2023];
};
void SIWBI2TX
( struct VARCHAR *inString, /* in: string to convert */
int *inCCSID,
struct VARGRAPH *outString,
short int *ninString, /* in: indic for string to co */
short int *nCCSID,
short int *noutString,
char *sqlstate, /* out: SQLSTATE */
char *fnName, /* in: family name of function*/
char *specificName, /* in: specific name of func */
char *message /* out: diagnostic message */
)
有了这个定义,输出字符串被放置在 outString->data 中并且应该被编码为 UTF-16。
- 我在第 3 项更改后遇到的另一个问题是在错误、诊断消息和 SQLCODE 停止工作的情况下。线索是在返回值中使用 UTF-16 时,消息和 SQLCODE 也必须使用 UTF-16。但具体的UTF-16。至于它们的定义没有改变,它们仍然被定义为 C char *,这意味着每个字符只有一个字节,它们预计只包含一个 UTF-16 代码的低字节。这种编码仅适用于英文文本和数字。但这对于错误消息和代码来说已经足够了。
我希望我的长篇文章对某人有所帮助。问题在于,与用户定义的函数和过程相关的 IBM 文档中没有此信息。