FreeTDS:如何设置参数 运行 存储过程的字符集
FreeTDS: How to set charset of parameters running stored procedure
我有一个 C 程序通过 FreeTDS 连接到 MSSQL 数据库。
我正在尝试执行一个 varchar 参数设置为类似“Saída Liberada”的存储过程,但它在 MS SQL 中以奇怪的字符存储,如下图所示:
这是我的 freetds.conf:
# $Id: freetds.conf,v 1.12 2007/12/25 06:02:36 jklowden Exp $
#
# This file is installed by FreeTDS if no file by the same
# name is found in the installation directory.
#
# For information about the layout of this file and its settings,
# see the freetds.conf manpage "man freetds.conf".
# Global settings are overridden by those in a database
# server specific section
[global]
# TDS protocol version
tds version = 8.0
# Whether to write a TDSDUMP file for diagnostic purposes
# (setting this to /tmp is insecure on a multi-user system)
dump file = /tmp/freetds.log
; debug flags = 0xffff
# Command and connection timeouts
; timeout = 10
; connect timeout = 10
# If you get out-of-memory errors, it may mean that your client
# is trying to allocate a huge buffer for a TEXT field.
# Try setting 'text size' to a more reasonable limit
text size = 64512
client charset = UTF-8
这是 tds 转储文件的部分内容:
log.c:196:Starting log file for FreeTDS 0.91
on 2016-05-17 19:19:41 with debug flags 0x4fff.
iconv.c:330:tds_iconv_open(0xaed19130, ISO-8859-1)
iconv.c:353:Using trivial iconv
iconv.c:187:local name for ISO-8859-1 is ISO-8859-1
iconv.c:187:local name for UTF-8 is UTF-8
iconv.c:187:local name for UCS-2LE is UCS-2LE
iconv.c:187:local name for UCS-2BE is UCS-2BE
iconv.c:349:setting up conversions for client charset "ISO-8859-1"
iconv.c:351:preparing iconv for "ISO-8859-1" <-> "UCS-2LE" conversion
iconv.c:391:preparing iconv for "ISO-8859-1" <-> "ISO-8859-1" conversion
iconv.c:394:tds_iconv_open: done
...
net.c:741:Sending packet
0000 01 01 00 84 00 00 00 00-20 45 58 45 43 20 55 50 |........ EXEC UP|
0010 5f 49 4e 53 45 52 54 4d-4f 56 49 4d 45 4e 54 4f |_INSERTM OVIMENTO|
0020 20 27 32 30 31 36 2d 30-35 2d 31 37 20 31 39 3a | '2016-0 5-17 19:|
0030 31 39 3a 33 31 2e 30 30-30 27 2c 27 30 30 30 30 |19:31.00 0','0000|
0040 30 30 30 30 30 30 36 34-38 33 30 35 37 30 33 30 |00000064 83057030|
0050 27 2c 27 53 27 2c 30 2c-32 2c 27 50 43 56 43 30 |','S',0, 2,'PCVC0|
0060 34 20 3d 20 53 61 c3 ad-64 61 20 4c 69 62 65 72 |4 = Sa.. da Liber|
0070 61 64 61 27 2c 34 2c 27-50 43 56 43 4d 41 4e 41 |ada',4,' PCVCMANA|
0080 47 45 52 27 - |GER'|
根据 freetds 日志,它将字符“í”(i 锐音符)作为 c3 广告发送,这意味着它正在将其作为 UTF-8(带锐音符的拉丁文小写字母 I)发送。
如何设置客户端或服务器,以便正确存储字符串?
更新 1:
# tsql -C
Compile-time settings (established with the "configure" script)
Version: freetds v0.91
freetds.conf directory: /etc
MS db-lib source compatibility: no
Sybase binary compatibility: yes
Thread safety: yes
iconv library: no
TDS version: 4.2
iODBC: no
unixodbc: yes
SSPI "trusted" logins: no
Kerberos: no
#
更新 2
连接代码:
ret = SQLDriverConnect(db_msserver_dbc_handle,
NULL, "Driver={FreeTDS};Server=FooBar;Port=1433;Database=Foo;UID=sa;PWD=pwd@123;APP=XPTO;TDS_Version=8.0;",
SQL_NTS, outstr, sizeof(outstr), &outstrlen,
SQL_DRIVER_COMPLETE);
经过多次尝试,我无法弄清楚为什么 freetds.conf 设置(客户端字符集和 tds 版本)没有得到遵守。至少,当我将 TDS_Version=8.0;ClientCharset=UTF-8 附加到 connection string 时,它起作用了!
"Driver={FreeTDS};Server=%s;Port=%s;Database=%s;UID=%s;PWD=%s;APP=%s;TDS_Version=8.0;ClientCharset=UTF-8"
此外,freetds 日志文件的 header 已更改,提及 UTF-8 转换:
log.c:196:Starting log file for FreeTDS 0.91
on 2016-05-18 15:58:49 with debug flags 0x4fff.
iconv.c:330:tds_iconv_open(0xaeb19118, UTF-8)
iconv.c:353:Using trivial iconv
iconv.c:187:local name for ISO-8859-1 is ISO-8859-1
iconv.c:187:local name for UTF-8 is UTF-8
iconv.c:187:local name for UCS-2LE is UCS-2LE
iconv.c:187:local name for UCS-2BE is UCS-2BE
iconv.c:349:setting up conversions for client charset "UTF-8"
iconv.c:351:preparing iconv for "UTF-8" <-> "UCS-2LE" conversion
iconv.c:391:preparing iconv for "ISO-8859-1" <-> "UCS-2LE" conversion
iconv.c:394:tds_iconv_open: done
我有一个 C 程序通过 FreeTDS 连接到 MSSQL 数据库。
我正在尝试执行一个 varchar 参数设置为类似“Saída Liberada”的存储过程,但它在 MS SQL 中以奇怪的字符存储,如下图所示:
这是我的 freetds.conf:
# $Id: freetds.conf,v 1.12 2007/12/25 06:02:36 jklowden Exp $
#
# This file is installed by FreeTDS if no file by the same
# name is found in the installation directory.
#
# For information about the layout of this file and its settings,
# see the freetds.conf manpage "man freetds.conf".
# Global settings are overridden by those in a database
# server specific section
[global]
# TDS protocol version
tds version = 8.0
# Whether to write a TDSDUMP file for diagnostic purposes
# (setting this to /tmp is insecure on a multi-user system)
dump file = /tmp/freetds.log
; debug flags = 0xffff
# Command and connection timeouts
; timeout = 10
; connect timeout = 10
# If you get out-of-memory errors, it may mean that your client
# is trying to allocate a huge buffer for a TEXT field.
# Try setting 'text size' to a more reasonable limit
text size = 64512
client charset = UTF-8
这是 tds 转储文件的部分内容:
log.c:196:Starting log file for FreeTDS 0.91
on 2016-05-17 19:19:41 with debug flags 0x4fff.
iconv.c:330:tds_iconv_open(0xaed19130, ISO-8859-1)
iconv.c:353:Using trivial iconv
iconv.c:187:local name for ISO-8859-1 is ISO-8859-1
iconv.c:187:local name for UTF-8 is UTF-8
iconv.c:187:local name for UCS-2LE is UCS-2LE
iconv.c:187:local name for UCS-2BE is UCS-2BE
iconv.c:349:setting up conversions for client charset "ISO-8859-1"
iconv.c:351:preparing iconv for "ISO-8859-1" <-> "UCS-2LE" conversion
iconv.c:391:preparing iconv for "ISO-8859-1" <-> "ISO-8859-1" conversion
iconv.c:394:tds_iconv_open: done
...
net.c:741:Sending packet
0000 01 01 00 84 00 00 00 00-20 45 58 45 43 20 55 50 |........ EXEC UP|
0010 5f 49 4e 53 45 52 54 4d-4f 56 49 4d 45 4e 54 4f |_INSERTM OVIMENTO|
0020 20 27 32 30 31 36 2d 30-35 2d 31 37 20 31 39 3a | '2016-0 5-17 19:|
0030 31 39 3a 33 31 2e 30 30-30 27 2c 27 30 30 30 30 |19:31.00 0','0000|
0040 30 30 30 30 30 30 36 34-38 33 30 35 37 30 33 30 |00000064 83057030|
0050 27 2c 27 53 27 2c 30 2c-32 2c 27 50 43 56 43 30 |','S',0, 2,'PCVC0|
0060 34 20 3d 20 53 61 c3 ad-64 61 20 4c 69 62 65 72 |4 = Sa.. da Liber|
0070 61 64 61 27 2c 34 2c 27-50 43 56 43 4d 41 4e 41 |ada',4,' PCVCMANA|
0080 47 45 52 27 - |GER'|
根据 freetds 日志,它将字符“í”(i 锐音符)作为 c3 广告发送,这意味着它正在将其作为 UTF-8(带锐音符的拉丁文小写字母 I)发送。
如何设置客户端或服务器,以便正确存储字符串?
更新 1:
# tsql -C
Compile-time settings (established with the "configure" script)
Version: freetds v0.91
freetds.conf directory: /etc
MS db-lib source compatibility: no
Sybase binary compatibility: yes
Thread safety: yes
iconv library: no
TDS version: 4.2
iODBC: no
unixodbc: yes
SSPI "trusted" logins: no
Kerberos: no
#
更新 2
连接代码:
ret = SQLDriverConnect(db_msserver_dbc_handle,
NULL, "Driver={FreeTDS};Server=FooBar;Port=1433;Database=Foo;UID=sa;PWD=pwd@123;APP=XPTO;TDS_Version=8.0;",
SQL_NTS, outstr, sizeof(outstr), &outstrlen,
SQL_DRIVER_COMPLETE);
经过多次尝试,我无法弄清楚为什么 freetds.conf 设置(客户端字符集和 tds 版本)没有得到遵守。至少,当我将 TDS_Version=8.0;ClientCharset=UTF-8 附加到 connection string 时,它起作用了!
"Driver={FreeTDS};Server=%s;Port=%s;Database=%s;UID=%s;PWD=%s;APP=%s;TDS_Version=8.0;ClientCharset=UTF-8"
此外,freetds 日志文件的 header 已更改,提及 UTF-8 转换:
log.c:196:Starting log file for FreeTDS 0.91
on 2016-05-18 15:58:49 with debug flags 0x4fff.
iconv.c:330:tds_iconv_open(0xaeb19118, UTF-8)
iconv.c:353:Using trivial iconv
iconv.c:187:local name for ISO-8859-1 is ISO-8859-1
iconv.c:187:local name for UTF-8 is UTF-8
iconv.c:187:local name for UCS-2LE is UCS-2LE
iconv.c:187:local name for UCS-2BE is UCS-2BE
iconv.c:349:setting up conversions for client charset "UTF-8"
iconv.c:351:preparing iconv for "UTF-8" <-> "UCS-2LE" conversion
iconv.c:391:preparing iconv for "ISO-8859-1" <-> "UCS-2LE" conversion
iconv.c:394:tds_iconv_open: done