在 《Linux系统上编译安装FreeTDS库文件》中已经安装好了 FreeTDS 的库文件,本文主要通过 C++ 代码简单调用 FreeTDS 来查询数据库中的数据。
本文将提到使用 F r e e T D S 库查询中文数据显示乱码的问题及解决方案 \color{red}{本文将提到使用FreeTDS库查询中文数据显示乱码的问题及解决方案} 本文将提到使用FreeTDS库查询中文数据显示乱码的问题及解决方案
调用Freetds来查询数据表
1. 首先新建.cpp源文件
首先我们新建一个 test.cpp 文件,并写入如下代码(代码中的数据库名,账号、密码、IP地址等根据你实际的环境修改。):
#include <stdio.h>
#include <string.h>
#include <sybfront.h> //freetds头文件
#include <sybdb.h> //freetds头文件
typedef unsigned char BYTE;
DBPROCESS *dbprocess; // 句柄: 连接sqlserver服务器地址和端口号
bool Init_DB(void)
{
try
{
dbinit();
}
catch(...)
{
return false;
}
return true;
}
bool Ftds_Connect_DB(const char* const szUser,
const char* const szPwd,
const char* const szSvr,
const char* const szDb)
{
if (!Init_DB())
{
return false;
}
LOGINREC *loginrec; //数据库连接对象
// Create database connection object
loginrec=dblogin();
// Set the login user name
DBSETLUSER(loginrec,szUser);
// Set the login password
DBSETLPWD(loginrec,szPwd);
// Connect SQL server server address and port, here is the connection
dbprocess = dbopen(loginrec, szSvr);
if(dbprocess == FAIL)
{
return false;
}
// 连接数据库
if(dbuse(dbprocess, szDb)==FAIL)
{
printf("Open data basename fail!...");
return false;
}
return true;
}
bool BindCol(int ncolnum, int bufflen, BYTE* pbuff)
{
RETCODE ret = dbbind(dbprocess, ncolnum, STRINGBIND, bufflen, pbuff);
if (ret != SUCCEED)
{
return false;
}
return true;
}
int DB_Test(void)
{
bool isconnectok = Ftds_Connect_DB("sa", "123456", "127.0.0.1:1433", "fy2000");
if (!isconnectok)
{
printf("database connect fail...\n");
}
char strSql[1024] = {0};
sprintf(strSql, "%s", "select * from tb_student_info");
dbcmd(dbprocess, strSql); //初始化查询数据指令
// 执行命令
if(dbsqlexec(dbprocess) == FAIL)
{
printf("Query Sql Exec error!...");
return false;
}
char name[20];
char age[20];
char height[20];
char weight[20];
int result_code;
while((result_code = dbresults(dbprocess)) != NO_MORE_RESULTS)
{
if(result_code == SUCCEED)
{
BindCol(1, 20, (BYTE*)name);
BindCol(2, 20, (BYTE*)age);
BindCol(3, 20, (BYTE*)height);
BindCol(4, 20, (BYTE*)weight);
// 跳到下一行
while(dbnextrow(dbprocess) != NO_MORE_ROWS)
{
char szresult[1024];
memset(szresult, 0, 1024);
sprintf(szresult, "%s\t%s\t%s\t%s\n", name, age, height, weight);
printf(szresult);
}
}
}
dbcancel(dbprocess);
dbclose(dbprocess);
printf("Execute sql success!...\n");
return 0;
}
int main()
{
DB_Test();
return 0;
}
2. 编写Makefile文件
新建一个 Makefile 文件,内容如下:
# 定义变量 cc 代表使用的编译器为g++, OBJC为生成可执行文件的依赖项
cc := g++
OBJC := test.o
# 定义可执行文件的依赖项和生成规则命令
a.out : $(OBJC)
$(cc) $(OBJC) -o a.out -lsybdb
# 定义依赖项中没有目标文件的依赖项和生成命令
test.o : test.cpp
$(cc) -c test.cpp
# 定义伪目标
.PHONY : clean rm_o
clean :
rm a.out $(OBJC)
rm_o :
rm $(OBJC)
3. 使用 make 命令编译程序
[root@localhost mytest]# make
g++ -c test.cpp
g++ test.o -o a.out -lsybdb
[root@localhost mytest]# ls
a.out Makefile test.cpp test.o
[root@localhost mytest]#
4. 执行 a.out 文件
[root@localhost mytest]# ./a.out
li 5 25 128
ming 4 27 124
shuai 6 35 130
hong 3 30 100
jaing 7 23 126
mei 5 24 110
Execute sql success!...
[root@localhost mytest]#
如上已经成功读取到了表中的数据。
上述查询的表数据都是数字和英文,显示一般没有问题,但是涉及到中文时,可能就会出现乱码的问题。
1. 环境版本
- 数据库:sqlserver 2017 安装在 Linux 系统本地
- 数据库排序规则:Chinese_PRC_CI_AS
2. 将 tb_student_info 中人名换成中文
name | class | age | hight |
---|---|---|---|
小丽 | 5 | 25 | 128 |
小民 | 4 | 27 | 124 |
小爽 | 6 | 35 | 130 |
小红 | 3 | 30 | 100 |
小江 | 7 | 23 | 126 |
小美 | 5 | 24 | 110 |
3. 用同样的方法查询
[root@localhost mytest]# ./a.out
?? 5 25 128
?? 4 27 124
?? 6 35 130
?? 3 30 100
?? 7 23 126
?? 5 24 110
Execute sql success!...
[root@localhost mytest]#
会发现,所有的中文名字都变成了问号,查询显示异常。这是因为数据库使用的字符集(排序规则)和FreeTDS默认的字符集(排序规则)不同导致的。
4 排序规则说明
查资料可知:
- Chinese_PRC_CI_AS:Chinese_PRC_指UNICODE字符集,即指针对大陆简体字UNICODE的排序规则。CI指不区分大小写;AS指区分重音。
- FreeTDS字符集由官网FreeTDS配置文件作用说明可知如下:
Name | Possible Values | Default | Meaning |
---|---|---|---|
client charset | any valid iconv character set | ISO-8859-1 | Makes FreeTDS use iconv to convert to and from the specified character set from UCS-2 in TDS 7.0 or above. FreeTDS uses iconv to convert all character data, so there’s no need to match the server’s charset to insert any characters the server supports. |
可以看出,在FreeTDS的配置文件中是可以设置字符集的,而如果没有设置,那么FreeTDS默认的字符集为 ISO-8859-1,此字符集支持部分于欧洲使用的语言。也就是说,在默认的情况下,只要是调用FreeTDS输出的字符,都会被转换为 ISO-8859-1 字符集字符。
- 由上可知数据库是 UNICODE 字符集,FreeTDS使用的是 ISO-8859-1 字符集,查询出的 UNICODE 字符集数据会被转换为 ISO-8859-1 字符集,而当前的linux系统不支持显示 ISO-8859-1 字符集。因此需要修改FreeTDS使用的字符集,又因为,最终要在Linux系统上显示使用,所以需要查看linux系统支持的字符集是什么。然后直接将系统字符集设置为FreeTDS转换输出的字符集就可以用正常显示了。
5. 查询Linux系统支持的字符集
查询命令使用 locale
[root@localhost mytest]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=
[root@localhost mytest]#
可以看到当前Linux系统的语言使用的字符集是UTF-8,LANG=zh_CN.UTF-8,因此需要将FreeTDS的字符集也设置为UTF-8,这样,FreeTDS就会将所有输出转换为UTF-8字符集。
6. 设置FreeTDS字符集
在配置文件 freetds.conf 中修改字符集。
- 查询文件所在位置
[root@localhost mytest]# find / -name freetds.conf
/usr/local/etc/freetds.conf
[root@localhost mytest]# vim /usr/local/etc/freetds.conf
- 修改
在 text size = 64512 配置项下一行加上 client charset = UTF-8 即可。
#
# 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 = auto
# 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
# To reduce data sent from server for BLOBs (like TEXT or
# IMAGE) try setting 'text size' to a reasonable limit
text size = 64512
client charset = UTF-8
# If you experience TLS handshake errors and are using openssl,
# try adjusting the cipher list (don't surround in double or single quotes)
# openssl ciphers = HIGH:!SSLv2:!aNULL:-DH
# A typical Sybase server
[egServer50]
host = symachine.domain.com
port = 5000
tds version = 5.0
# A typical Microsoft server
[egServer73]
host = ntmachine.domain.com
port = 1433
tds version = 7.3
7.重新查询
[root@localhost mytest]# ./a.out
小丽 5 25 128
小民 4 27 124
小爽 6 35 130
小红 3 30 100
小江 7 23 126
小美 5 24 110
Execute sql success!...
[root@localhost mytest]#