在 ChineseTaiwan Collat​​ion 中,VARCHAR 内存缓冲区似乎正在中断

6 sql-server collation

我很难用英语写一些东西。我希望你明白。我使用了翻译器并对其进行了审查。

我创建了两个临时数据库。排序规则分别是“Korea_Wansung_CI_AS”和“Chinese_Taiwan_Stroke_CI_AS”。

我创建了一个带有类型列的临时表,VARCHAR(2048)我刚刚在INSERT这里创建了一个用于此表数据的过程。

当从使用 c++ oledb 的服务器调用存储过程时,该VARCHAR值被加密并作为 UTF-8 发送。

我们发送

  • '???' -> 'Korean_Wansung'¨
  • “??????” -> 'Chinese_Taiwan'。

我已经通过调试验证该值是使用普通 UTF-8 加密的。

  • '???' -> UTF-8 -> '\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4'

  • “??????” -> UTF-8 -> '\xe9\x9f\x93\xe5\x9c\x8b\xe4\xba\xba\xe5\xad\xb8\xe5\x8f\xb0'

在这里,我有一个问题。

当通过数据库中的SELECT语句回读该表时,我们发现对于Korean_Wansung,字符串'matched by the Code Page 949' 正常出现。

但不适用于Chinese_Taiwan。存储在内存中的值本身似乎已损坏。

如果您从服务器获取该值并对其进行解码,那么对于 Korean_Wansung 而言,原始字符将显示为正常字符。

但是在中国的情况下,它不会正常出来。

我需要你的帮助。

如果您需要更多信息,我们会迅速回复您并上传。

谢谢你。

gbn*_*gbn 9

您需要确保字符串(存储过程参数)发送N VARCHAR

DECLARE @CollationTest table (
     ID int NOT NULL,
     KoreanV varchar(2048) COLLATE Korean_Wansung_CI_AS NULL ,
     KoreanNV nvarchar(2048) COLLATE Korean_Wansung_CI_AS NULL ,
     ChineseTaiwanV varchar(2048) COLLATE Chinese_Taiwan_Stroke_CI_AS NULL ,
     ChineseTaiwanNV nvarchar(2048) COLLATE Chinese_Taiwan_Stroke_CI_AS NULL 
    )

INSERT @CollationTest VALUES (1,
    '???',
    N'???', 
    '?????', 
    N'?????'
)

INSERT @CollationTest VALUES (2,
    N'???',
    N'???', 
    N'?????', 
    N'?????'
)
SELECT * FROM @CollationTest
Run Code Online (Sandbox Code Playgroud)


Sol*_*zky 6

不,您不需要确保存储过程参数是NVARCHAR. 虽然同时使用NVARCHAR参数和列数据类型都有优势,但韩语文本正确存储在VARCHAR列中这一事实证明NVARCHAR没有必要。

当从使用 c++ oledb 的服务器调用存储过程时,VARCHAR 值被加密并作为 UTF-8 发送。

直到 SQL Server 2019(几周前才作为测试版向公众发布)之前,SQL Server 内部根本不支持 UTF-8。因此,您可能要向 OLEDB 驱动程序提供 UTF-8 值,但该驱动程序会将 UTF-8 字节转换为目标代码页的等效字节,目标代码页应该是当前数据库默认排序规则使用的代码页。“当前”数据库是您连接到的数据库(如果没有USE执行任何语句),或者是由最近的USE语句设置的数据库。

这意味着,即使数据库的默认排序规则使用代码页950,而目标列也有使用代码页950的归类,你可能无法得到正确的数据插入如果“当前”数据库中的时间INSERT(或EXEC中包含INSERT)的存储过程具有使用不支持您插入的所有字符的代码页的默认排序规则。

我在该问题的评论中发布了几个问题,回答这些问题将极大地帮助我提供更具体的答案/解释(特别是更新问题以包含从未正确插入的值返回的确切字节)。但是,在此之前,我可以通过以下查询说明这一切是如何工作的:

DECLARE @Test TABLE
(
  [Source] VARCHAR(50),
  [Value] VARCHAR(20) COLLATE Chinese_Taiwan_Bopomofo_90_CI_AS,
  [HexOfCP950] AS (CONVERT(VARBINARY(20), [Value])),
  [ValueAsUTF16] AS (CONVERT(NVARCHAR(20), [Value])),
  [HexOfUTF16] AS (CONVERT(VARBINARY(20), CONVERT(NVARCHAR(50), [Value]))),
  [NumBytes] AS (DATALENGTH([Value]))
);

-- The following 2 INSERTs work no matter what the current DB Collation is:
INSERT INTO @Test VALUES ('UTF-16 characters', N'?????');
INSERT INTO @Test VALUES ('CodePage 950 bytes', 0xC1FAB0EAA448BEC7A578);

-- The following 3 INSERTs simulate the effect of passing in 8-bit characters,
--  which depend on the current DB's default Collation:
INSERT INTO @Test VALUES ('CodePage 950 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Chinese_Taiwan_Bopomofo_90_CI_AS));

INSERT INTO @Test VALUES ('CodePage 949 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Korean_Wansung_CI_AS));

INSERT INTO @Test VALUES ('CodePage 936 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Chinese_Simplified_Stroke_Order_100_CI_AS));

INSERT INTO @Test VALUES ('CodePage 932 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Japanese_XJIS_100_CI_AS));

INSERT INTO @Test VALUES ('CodePage 1252 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Latin1_General_100_CI_AS));


SELECT * FROM @Test;
Run Code Online (Sandbox Code Playgroud)

这将返回以下内容:

DECLARE @Test TABLE
(
  [Source] VARCHAR(50),
  [Value] VARCHAR(20) COLLATE Chinese_Taiwan_Bopomofo_90_CI_AS,
  [HexOfCP950] AS (CONVERT(VARBINARY(20), [Value])),
  [ValueAsUTF16] AS (CONVERT(NVARCHAR(20), [Value])),
  [HexOfUTF16] AS (CONVERT(VARBINARY(20), CONVERT(NVARCHAR(50), [Value]))),
  [NumBytes] AS (DATALENGTH([Value]))
);

-- The following 2 INSERTs work no matter what the current DB Collation is:
INSERT INTO @Test VALUES ('UTF-16 characters', N'?????');
INSERT INTO @Test VALUES ('CodePage 950 bytes', 0xC1FAB0EAA448BEC7A578);

-- The following 3 INSERTs simulate the effect of passing in 8-bit characters,
--  which depend on the current DB's default Collation:
INSERT INTO @Test VALUES ('CodePage 950 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Chinese_Taiwan_Bopomofo_90_CI_AS));

INSERT INTO @Test VALUES ('CodePage 949 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Korean_Wansung_CI_AS));

INSERT INTO @Test VALUES ('CodePage 936 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Chinese_Simplified_Stroke_Order_100_CI_AS));

INSERT INTO @Test VALUES ('CodePage 932 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Japanese_XJIS_100_CI_AS));

INSERT INTO @Test VALUES ('CodePage 1252 characters', CONVERT(VARCHAR(20), N'?????'
                                   COLLATE Latin1_General_100_CI_AS));


SELECT * FROM @Test;
Run Code Online (Sandbox Code Playgroud)

所以似乎在 SQL Server 支持的所有 4 个双字节字符集中都可以找到这些汉字。所以这应该对你有用。由于它不起作用,您需要回答我发布的问题。

如果您使用不支持中文字符的代码页从具有默认排序规则的数据库执行存储过程,这可以解释为什么它们没有被正确存储。但:

  1. 我们确实看到所有四个双字节字符集都支持汉字,所以它必须是非中文、非韩文、非日文的校对,
  2. 如果韩文字符被正确插入,那么它是从与中文 INSERT proc 被调用的数据库不同的数据库中调用的。

如果用于 INSERT 中文文本的存储过程在中文数据库中,则:

  1. 有可能中文数据库的默认排序规则实际上不是中文排序规则,和/或
  2. 有可能中文数据库中表中列的Collat​​ion实际上并不是中文Collat​​ion。

也有可能是存储过程的输入参数VARCHAR(6)VARCHAR(10)(至少)需要保存汉字的时候。

另外,您是否将非 UTF-8 数据编码(不加密)为 UTF-8 只是为了发送到 SQL Server?如果是,那就没必要了。

最后,如果您遇到错误,请提供确切的错误消息。谢谢。