Sql server freebcp:“您必须遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他有关法律法规。”;Unicode数据是列的奇数字节大小。应为偶数字节大小“;

Sql server freebcp:“您必须遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他有关法律法规。”;Unicode数据是列的奇数字节大小。应为偶数字节大小“;,sql-server,unicode,sql-server-2012,character-encoding,freetds,Sql Server,Unicode,Sql Server 2012,Character Encoding,Freetds,此文件工作正常(UTF-8): 此文件导致错误(UTF-8): 以下是信息: $ freebcp 'DB.dbo.table' in bad.txt ... -c Starting copy... Msg 20050, Level 4 Attempt to convert data stopped by syntax error in source field Msg 4895, Level 16, State 2 Server '...', Line 1 Unicode data i

此文件工作正常(UTF-8):

此文件导致错误(UTF-8):

以下是信息:

$ freebcp 'DB.dbo.table' in bad.txt ... -c
Starting copy...
Msg 20050, Level 4
Attempt to convert data stopped by syntax error in source field

Msg 4895, Level 16, State 2
Server '...', Line 1
    Unicode data is odd byte size for column 2. Should be even byte size.
Msg 20018, Level 16
General SQL Server error: Check messages from the SQL Server
唯一的区别是最后一个字符,即unicode 2018(左单引号)

知道是什么导致了这个错误吗

SQL Server使用UTF-16LE(尽管TDS从UCS-2LE开始,我相信可以切换)

有问题的栏目是
nvarchar(200)

以下是错误发生前发送的数据包:

packet.c:741:Sending packet
0000 07 01 00 56 00 00 01 00-81 02 00 00 00 00 00 08 |...V.... ........|
0010 00 38 09 67 00 65 00 6f-00 6e 00 61 00 6d 00 65 |.8.g.e.o .n.a.m.e|
0020 00 69 00 64 00 00 00 00-00 09 00 e7 90 01 09 04 |.i.d.... ...ç....|
0030 d0 00 34 04 6e 00 61 00-6d 00 65 00 d1 ee 70 04 |Ð.4.n.a. m.e.Ñîp.|
0040 00 13 00 62 01 61 00 77-00 2b 01 20 00 52 00 69 |...b.a.w .+. .R.i|
0050 00 66 00 01 01 18      -                        |.f....|

这可能是源文件的编码问题

由于您使用的是非标准字符,所以源文件本身应该是unicode。其他编码使用不同的字节计数(一个到三个)对单个字符进行编码。例如,您的
Unicode 2018
是UTF-8格式的
0xE2 0x80 0x98

您的数据包以
.R.i.f.|
结尾,而您的
ā'
应该在这里。错误显示为服务器“…”,第1行


尝试找出源文件的编码(同时查看
大端和小端
),并尝试将文件转换为可靠的unicode格式。

更新:此问题显然已在2016-11-04发布的FreeTDS v1.00.16中修复


我可以使用FreeTDS v1.00.15复制您的问题。它显然像是
freebcp
中的一个bug,当文本字段的最后一个字符具有格式为
U+20xx
的Unicode代码点时,它会导致失败。(感谢@srutzky纠正了我关于原因的结论。)正如你所指出的,这是有效的

291054ŢawīRifā
。。。而这失败了

291054ŢawīRifā'
。。。但我发现这同样有效:

291054ŢawīRifāx
因此,一个难看的解决方法是对输入文件运行一个脚本,在每个文本字段中附加一个低阶非空格Unicode字符(例如,
x
,即
U+0078
,如上例所示),使用
freebcp
上传数据,然后对导入的行运行
UPDATE
语句以去除多余的字符

就个人而言,我倾向于从FreeTDS切换到Microsoft针对Linux的SQL Server ODBC驱动程序,其中包括
bcp
sqlcmd
实用程序,安装时使用以下说明:

我只是在Xubuntu 16.04下对它进行了测试,虽然我不得不稍微调整一下程序,使用
libssl.so.1.0.0
而不是
libssl.so.0.9.8
(对于
libcrypto
),但一旦安装了
bcp
,微软的
freebcp
实用程序就成功了

如果用于Linux的SQL Server ODBC驱动程序无法在Mac上运行,那么另一种选择是使用用于SQL Server的Microsoft JDBC驱动程序6.0和少量Java代码,如下所示:

connectionUrl=“jdbc:sqlserver://servername:49242"
+“databaseName=myDb”
+“integratedSecurity=false”;
字符串myUserid=“sa”,myPassword=“whatever”;
字符串dataFileSpec=“C:/Users/Gord/Desktop/bad.txt”;
试一试(
Connection conn=DriverManager.getConnection(connectionUrl、myUserid、myPassword);
SQLServerBulkCSVFileRecord fileRecord=新SQLServerBulkCSVFileRecord(dataFileSpec,“UTF-8”,“\t”,false);
SQLServerBulkCopy bulkCopy=新SQLServerBulkCopy(conn)){
addColumnMetadata(1,“col1”,java.sql.Types.NVARCHAR,50,0);
addColumnMetadata(2,“col2”,java.sql.Types.NVARCHAR,50,0);
bulkCopy.setDestinationTableName(“dbo.freebcptest”);
bulkCopy.writeToServer(文件记录);
}捕获(例外e){
e、 printStackTrace(System.err);
}
这可能会解决这个问题:

inf/etc/freetds/freetds.conf

加:

还可以找到有关标志使用的信息
utf-16

在数据库范围内使用utf-16而不是使用UCS-2
字符编码使用UTF-16。较新的Windows版本使用此选项
编码而不是UCS-2。如果客户端
假设一个字符总是2个字节


这个问题与UTF-8无关,因为传输数据包(问题的底部)中显示的数据是UTF-16 Little-Endian(正如SQL Server所期望的那样)。它是非常好的UTF-16LE,除了缺少最后一个字节,就像错误消息所暗示的那样

问题很可能是freetds中的一个小错误,它错误地应用了从可变长度字符串字段中去掉尾随空格的逻辑。你说没有尾随空格?好吧,如果它没有被切掉,那么它会更清晰一些(但是,如果它没有被切掉,就不会有这个错误)。那么,让我们看看数据包是什么,看看我们是否可以重建它

数据中的错误可能被忽略,因为数据包包含偶数个字节。但并不是所有字段都是双字节的,所以它不需要是偶数。如果我们知道好的数据是什么(在错误之前),那么我们可以在数据中找到一个起点并向前移动。最好从
Ţ
开始,因为它有望高于255/FF值,因此需要2个字节。下面的任何内容都将有一个
00
,并且许多字符的两侧都有该字符。虽然我们应该能够假设小端编码,但最好是确定地知道。为此,我们需要至少一个具有两个非
00
字节和不同字节的字符(两个字节中的一个字符都是
01
,这无助于确定顺序)。此字符串字段的第一个字符
Ţ
,确认这一点,因为它是代码点0162,但在数据包中显示为
62 01

以下是与数据包顺序相同的字符,它们的UTF-16 LE valu
$ freebcp 'DB.dbo.table' in bad.txt ... -c
Starting copy...
Msg 20050, Level 4
Attempt to convert data stopped by syntax error in source field

Msg 4895, Level 16, State 2
Server '...', Line 1
    Unicode data is odd byte size for column 2. Should be even byte size.
Msg 20018, Level 16
General SQL Server error: Check messages from the SQL Server
packet.c:741:Sending packet
0000 07 01 00 56 00 00 01 00-81 02 00 00 00 00 00 08 |...V.... ........|
0010 00 38 09 67 00 65 00 6f-00 6e 00 61 00 6d 00 65 |.8.g.e.o .n.a.m.e|
0020 00 69 00 64 00 00 00 00-00 09 00 e7 90 01 09 04 |.i.d.... ...ç....|
0030 d0 00 34 04 6e 00 61 00-6d 00 65 00 d1 ee 70 04 |Ð.4.n.a. m.e.Ñîp.|
0040 00 13 00 62 01 61 00 77-00 2b 01 20 00 52 00 69 |...b.a.w .+. .R.i|
0050 00 66 00 01 01 18      -                        |.f....|
client charset = UTF-8