*********************注意:为了保证文章的完整性和全面性,作者会不定期对文章进行更新和修正*********************
freetds其实就是个软件而且是一款开源软件,而且这个软件支持相当多的系统,比如Linux, Unix, Windows, 当你在Linux上安装了这个软件并且配置了这个软甲的环境变量,你就可以在shell上使用相关的命令来直接操作这个软件来实现我们想要的功能, 同时我们在安装完freetds软件的时候, freetds软件的发行商也提供给我们了相关的函数库和头文件,使得我们在自己开发的程序中也可以调用freetds的相关接口来实现我们想要的功能.
2.为什么我们要使用freetds, freetds的功能是什么?
我们都知道,向我们在Linux上使用的数据库一般都为MySQL, MySQL是一款开源数据库,当你在Linux上安装MySQL的时候, MySQL会提供给你连接它的方式, 但是当我们连接出了MySQL以外的一些比较特殊的数据库是, 比如Windows上的不开源的SQLServer时怎么办? 微软好像也没有针对Linux开放出API, 因为这个软件就是针对于Windows设计的, 这个时候我们就可以使用三方软件freetds来完成对SQLServer的连接和操作, 而且freetds不仅支持SQLServer而且还支持Sybase databases(塞班数据库).
**注意:SQLServer的默认编码可能是GBK, 而我们在Linux下编程使用的默认编码集一般为UTF-8, 当我们在Linux程序中使用SQL语句操作SQLServer时候特别是我们的SQL语句中有中文的时候, SQL语句从UTF-8转变为GBK,会产生乱码, 使得你永远都无法将SQL语句执行成功, 而且程序也不会给出明显的错误提示
**注意:我这边再介绍几个变量:
<1>RETCODE:我们在头文件sybdb.h头文件中发现了他的先关定义, 其实RETCODE就是int, 原始代码是:typedef int RETCODE
<2>SUCCEED:这个值也是int, 他的定义也位于sybdb.h上, 原始代码为:#define SUCCEED 1
<3>FAIL:这个值也是int, 他的定义也位于sybdb.h上, 原始代码为:#define FAIL 0
(1)dbinit()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbinit(void);
返回值:RETCODE:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:无
函数作用:在你调用freetds的其他的函数的时候一定要先调用这个函数, 这个函数的作用就是进行一些初始化工作, 好比如为结构体分配空间, 还有读取你Linux上的一些配置文件, 来确定日期格式和其他信息
(2)dblogin()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
LOGINREC* dblogin(void)
返回值:<1>这个函数失败时返回NULL
<2>成功时返回一个LOGINREC指针, 这是一个结构体, 这个结构体中包含了连接数据库的相关参数
LOGINREC结构体中的内容:
char* client_charset 客户端字符编码集
char* client_hostname 连接数据库的IP
int connect_timeout 连接数据库的超时时间
char* password 连接数据库时使用的密码
int query_timeout 发送请求命令时的超时时间
char* username 连接数据库的用户名称
参数:无
函数作用:创建一个LOGINRES指针,并且返回它
(3)dbsetlname()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbsetlname(LOGINREC* login, const char* value, int which)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>value:我们要设置的选项的值
<3>which:我们要设置的选项, 好比如: DBSETUSER(int类型)....
函数作用:设置LOGINREC中的相关的选项的值
(4)DBSETUSER()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBSETUSER(LOGINREC* login, char* UserName)
返回值:RETCODE:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>UserName:登录数据库的用户的名称
函数作用:向LOGINREC结构体中设置登录用户的名称
函数介绍:其实这个函数就是宏定义函数, 在头文件sybdb.h是这么定义的:#define DBSETLUSER(x,y) dbsetlname((x), (y), DBSETUSER)
(5)DBSETLPWD()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBSETLPWD(LOGINREC* login, char* PassWord)
返回值:RETCODE:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>PassWord:登录数据库的用户的密码
函数作用:向LOGINREC结构体中设置登录用户的密码
函数介绍:其实这个函数就是宏定义函数, 在头文件sybdb.h是这么定义的:#define DBSETLPWD(x,y) dbsetlname((x), (y), DBSETPWD)
(6)dbopen()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBPROCESS* dbopen(LOGINREC* login, const char* server)
返回值:<1>成功时返回DBPROCESS*, 一个成功连接到数据库的句柄
<2>失败时返回NULL
参数:<1>LOGINREC*:一个LOGINREC指针, 指针中一定要保存了连接使用户的用户名称, 以及用户的
<2>server:要连接数据库的IP地址
函数作用:连接到数据库, 并且返回成功连接的句柄
(7)dbuse()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbuse(DBPROCESS* dbproc, const char* name)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数 :<1>dbproc:已经连接到数据库的连接句柄
<2>name:要使用的数据库的名字
函数作用:使用SQLServer中的具体的某个数据库, 相当于在数据库中执行use XXXXdatabase命令, 这个函数一定要在dbopen()之后运行
(8)dbcmd()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbcmd(DBPROCESS* dbproc, const char cmdstrmg[])
返回值:<1>执行成功时返回SUCCEED <2>执行失败时返回FAIL
参数:<1>dbproc:已经连接到某个数据库的句柄,其实就是执行完dbuse()之后的句柄
<2>cmdstrmg:要执行的sql命令
函数作用:这个函数最好在执行完dbuse之后运行,这个函数的作用其实就是将cmdstrmg这个SQL命令保存到dbproc指针指向的命令缓存中,等待运行
(9)dbsqlexec()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbsqlexec(DBPROCESS* dbproc)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:<1>保存了SQL命令的数据库连接句柄, 其实就是执行了dbcmd()函数之后的SQL连接句柄
函数作用:将连接句柄中缓存中保存的命令送到数据库中执行, 并且等待执行的结果, 再将结果返回
(10)dbresults()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbresults(DBPROCESS* dbproc)
返回值:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:dbproc:运行了dbsqlexec()函数之后的数据库连接句柄
函数作用:这个函数的作用就是用来判断函数dbsqlexec()执行的命令是否执行成功
(11)dbind()
函数原型:
#include <sybfront.h>
#include <stbdb.h>
RETCODE dbind(DBPROCESS* dbproc, int column, int vartype, DBINT valen, BYTE* varaddr)
返回值:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>dbproc:保存了函数运行结果的数据库连接句柄
<2>column:你在数据库中查找到的数据的列数, 顺序以及sql语句为准, 起始数据为1
<3>vartype:数据的类型, 既是要接受从数据库取出来的本级数据的类型
<4>varlen:保存取出数据的本机数据的大小
<5>varaddr:保存取出数据的本机数据的地址指针
函数作用:dbsqlexec()函数运行之后, 返回的结果不是单个数据, 而是多个数据的数据结果集合, 这个结果集合为行和列组成, 行就是一行数据,而列就是字段名称, 我们使用这个函数可以将结果集的column列的字段绑定到varaddr指向的本地的数据
(12)dbnextrow()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbnextrow(DBPROCESS* dbproc)
返回值:<1>NO_MORE_ROWS:结果集中没有更多的数据
参数:<1>dbproc:保存了查询结果的数据库连接句柄
函数作用:这个函数最好在dbind()函数调用之后调用, 我们在之前使用的dbind()函数, 将具体的字段和本机值绑定到了一起, 而dbnextrow()的作用就是查询结果集合中的下一行数据, 每当我们使用dbnextrow()函数的时候, 本地值中保存的绑定的指定的字段的值都会变为当前结果集那一行的对应字段的值
(13)dbclose()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
void dbclose(DBPROCESS* dbproc)
返回值:无
参数:dbproc:一个连接好数据库的连接句柄
作用:关闭和数据库的连接, 并且释放这个连接句柄的资源
相关代码:
freetds其实就是个软件而且是一款开源软件,而且这个软件支持相当多的系统,比如Linux, Unix, Windows, 当你在Linux上安装了这个软件并且配置了这个软甲的环境变量,你就可以在shell上使用相关的命令来直接操作这个软件来实现我们想要的功能, 同时我们在安装完freetds软件的时候, freetds软件的发行商也提供给我们了相关的函数库和头文件,使得我们在自己开发的程序中也可以调用freetds的相关接口来实现我们想要的功能.
2.为什么我们要使用freetds, freetds的功能是什么?
我们都知道,向我们在Linux上使用的数据库一般都为MySQL, MySQL是一款开源数据库,当你在Linux上安装MySQL的时候, MySQL会提供给你连接它的方式, 但是当我们连接出了MySQL以外的一些比较特殊的数据库是, 比如Windows上的不开源的SQLServer时怎么办? 微软好像也没有针对Linux开放出API, 因为这个软件就是针对于Windows设计的, 这个时候我们就可以使用三方软件freetds来完成对SQLServer的连接和操作, 而且freetds不仅支持SQLServer而且还支持Sybase databases(塞班数据库).
3.freetds的相关函数介绍
一下相关函数接口用于freetds v0.91
**注意:我们在要使用freetds进行开发时候一定要引用freetds的相关头文件sybfront.h和sybdb.h, 同时我们在编写Makefile的使用也要连接freetds的相关函数库-lsybdb, 否则头文件是找不到函数的原型的**注意:SQLServer的默认编码可能是GBK, 而我们在Linux下编程使用的默认编码集一般为UTF-8, 当我们在Linux程序中使用SQL语句操作SQLServer时候特别是我们的SQL语句中有中文的时候, SQL语句从UTF-8转变为GBK,会产生乱码, 使得你永远都无法将SQL语句执行成功, 而且程序也不会给出明显的错误提示
**注意:我这边再介绍几个变量:
<1>RETCODE:我们在头文件sybdb.h头文件中发现了他的先关定义, 其实RETCODE就是int, 原始代码是:typedef int RETCODE
<2>SUCCEED:这个值也是int, 他的定义也位于sybdb.h上, 原始代码为:#define SUCCEED 1
<3>FAIL:这个值也是int, 他的定义也位于sybdb.h上, 原始代码为:#define FAIL 0
(1)dbinit()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbinit(void);
返回值:RETCODE:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:无
函数作用:在你调用freetds的其他的函数的时候一定要先调用这个函数, 这个函数的作用就是进行一些初始化工作, 好比如为结构体分配空间, 还有读取你Linux上的一些配置文件, 来确定日期格式和其他信息
(2)dblogin()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
LOGINREC* dblogin(void)
返回值:<1>这个函数失败时返回NULL
<2>成功时返回一个LOGINREC指针, 这是一个结构体, 这个结构体中包含了连接数据库的相关参数
LOGINREC结构体中的内容:
char* client_charset 客户端字符编码集
char* client_hostname 连接数据库的IP
int connect_timeout 连接数据库的超时时间
char* password 连接数据库时使用的密码
int query_timeout 发送请求命令时的超时时间
char* username 连接数据库的用户名称
参数:无
函数作用:创建一个LOGINRES指针,并且返回它
(3)dbsetlname()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbsetlname(LOGINREC* login, const char* value, int which)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>value:我们要设置的选项的值
<3>which:我们要设置的选项, 好比如: DBSETUSER(int类型)....
函数作用:设置LOGINREC中的相关的选项的值
(4)DBSETUSER()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBSETUSER(LOGINREC* login, char* UserName)
返回值:RETCODE:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>UserName:登录数据库的用户的名称
函数作用:向LOGINREC结构体中设置登录用户的名称
函数介绍:其实这个函数就是宏定义函数, 在头文件sybdb.h是这么定义的:#define DBSETLUSER(x,y) dbsetlname((x), (y), DBSETUSER)
(5)DBSETLPWD()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBSETLPWD(LOGINREC* login, char* PassWord)
返回值:RETCODE:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>LOGINREC*:一个LOGINREC指针
<2>PassWord:登录数据库的用户的密码
函数作用:向LOGINREC结构体中设置登录用户的密码
函数介绍:其实这个函数就是宏定义函数, 在头文件sybdb.h是这么定义的:#define DBSETLPWD(x,y) dbsetlname((x), (y), DBSETPWD)
(6)dbopen()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
DBPROCESS* dbopen(LOGINREC* login, const char* server)
返回值:<1>成功时返回DBPROCESS*, 一个成功连接到数据库的句柄
<2>失败时返回NULL
参数:<1>LOGINREC*:一个LOGINREC指针, 指针中一定要保存了连接使用户的用户名称, 以及用户的
<2>server:要连接数据库的IP地址
函数作用:连接到数据库, 并且返回成功连接的句柄
(7)dbuse()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbuse(DBPROCESS* dbproc, const char* name)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数 :<1>dbproc:已经连接到数据库的连接句柄
<2>name:要使用的数据库的名字
函数作用:使用SQLServer中的具体的某个数据库, 相当于在数据库中执行use XXXXdatabase命令, 这个函数一定要在dbopen()之后运行
(8)dbcmd()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbcmd(DBPROCESS* dbproc, const char cmdstrmg[])
返回值:<1>执行成功时返回SUCCEED <2>执行失败时返回FAIL
参数:<1>dbproc:已经连接到某个数据库的句柄,其实就是执行完dbuse()之后的句柄
<2>cmdstrmg:要执行的sql命令
函数作用:这个函数最好在执行完dbuse之后运行,这个函数的作用其实就是将cmdstrmg这个SQL命令保存到dbproc指针指向的命令缓存中,等待运行
(9)dbsqlexec()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbsqlexec(DBPROCESS* dbproc)
返回值:<1>成功时返回SUCCEED <2>失败时返回FAIL
参数:<1>保存了SQL命令的数据库连接句柄, 其实就是执行了dbcmd()函数之后的SQL连接句柄
函数作用:将连接句柄中缓存中保存的命令送到数据库中执行, 并且等待执行的结果, 再将结果返回
(10)dbresults()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbresults(DBPROCESS* dbproc)
返回值:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:dbproc:运行了dbsqlexec()函数之后的数据库连接句柄
函数作用:这个函数的作用就是用来判断函数dbsqlexec()执行的命令是否执行成功
(11)dbind()
函数原型:
#include <sybfront.h>
#include <stbdb.h>
RETCODE dbind(DBPROCESS* dbproc, int column, int vartype, DBINT valen, BYTE* varaddr)
返回值:<1>函数执行成功时返回SUCCEED <2>函数执行失败时返回FAIL
参数:<1>dbproc:保存了函数运行结果的数据库连接句柄
<2>column:你在数据库中查找到的数据的列数, 顺序以及sql语句为准, 起始数据为1
<3>vartype:数据的类型, 既是要接受从数据库取出来的本级数据的类型
<4>varlen:保存取出数据的本机数据的大小
<5>varaddr:保存取出数据的本机数据的地址指针
函数作用:dbsqlexec()函数运行之后, 返回的结果不是单个数据, 而是多个数据的数据结果集合, 这个结果集合为行和列组成, 行就是一行数据,而列就是字段名称, 我们使用这个函数可以将结果集的column列的字段绑定到varaddr指向的本地的数据
(12)dbnextrow()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
RETCODE dbnextrow(DBPROCESS* dbproc)
返回值:<1>NO_MORE_ROWS:结果集中没有更多的数据
参数:<1>dbproc:保存了查询结果的数据库连接句柄
函数作用:这个函数最好在dbind()函数调用之后调用, 我们在之前使用的dbind()函数, 将具体的字段和本机值绑定到了一起, 而dbnextrow()的作用就是查询结果集合中的下一行数据, 每当我们使用dbnextrow()函数的时候, 本地值中保存的绑定的指定的字段的值都会变为当前结果集那一行的对应字段的值
(13)dbclose()
函数原型:
#include <sybfront.h>
#include <sybdb.h>
void dbclose(DBPROCESS* dbproc)
返回值:无
参数:dbproc:一个连接好数据库的连接句柄
作用:关闭和数据库的连接, 并且释放这个连接句柄的资源
相关代码:
//其他的头文件不给于列出
#include <sybfront.h>
#include <sybdb.h>
//建立到MSSQL数据库的连接------------------------
DBINT result_code; //定义保存数据库交易结果的类型
dbinit(); //使用dbinit()函数, 进行freetds操作之前的初始化操作
LOGINREC *loginrec = dblogin(); //建立一个到数据库的连接的句柄
DBSETLUSER(loginrec, Q_SQLUser); //向句柄中添加连接数据库的用户
DBSETLPWD(loginrec, Q_SQLPassword); //向数据库连接句柄中添加密码
DBPROCESS *dbprocess = dbopen(loginrec, Q_SQLServer); //连接数据库,并返回数据库连接结果的句柄
if(dbprocess == FAIL) //如果连接失败
{
fprintf(stderr, "Connect Fail\n"); //在标准错误中输出信息
exit(EXIT_FAILURE); //进程异常退出
}
else //如果连接成功
{
printf("Connect success\n");
}
if(dbuse(dbprocess, Q_SQLName) == FAIL) //使用某个数据库,如果使用失败
{
dbclose(dbprocess); //关闭数据库连接句柄, 并且回收相关资源
exit(EXIT_FAILURE); //进程异常退出
}
//开始进行数据库中数据查询的工作------------------
char mssqlbuf[1024]; //定义保存数据库查询语句的字符串
memset(mssqlbuf, 0x00, sizeof(mssqlbuf)); //开始初始化字符串
sprintf(mssqlbuf, "SELECT name, age FROM testTable"); //组装操作sql的语句, 将sql语句保存到mssqlbuf
dbcmd(dbprocess, mssqlbuf); //将刚刚组装好的sql命令, 使用dbcmd命令保存到数据库连接句柄的缓存中
if(dbsqlexec(dbprocess) == FAIL) //如果执行的命令失败
{
dbclose(dbprocess); //关闭数据库操作进程
exit(EXIT_FAILURE); //程序异常退出
}
char name[100]; //定义两个变量来保存绑定出来的数据
char age[10];
memset(name, 0x00, sizeof(name)); //对数组进行初始化
memset(age, 0x00, sizeof(age));
//开始对数据取出的进行操作-------------------------
if((result_code = dbresults(dbprocess)) != NO_MORE_RESULTS && result_code == SUCCEED) //如果sql命令执行成功
{
//开始绑定数据
dbbind(dbprocess, 1, CHARBIND, (DBCHAR)0, (BYTE*)name); //将数据库中查找到的name(sql命令中我们查找的时候name位于结果的第一个), 绑定给本地的name
dbbind(dbprocess, 2, CHARBIND, (DBCHAR)0, (BYTE*)age); //将数据库中查找到的age(sql命令中我们查找的时候age位于结果的第二个), 绑定给本地的age
while(dbnextrow(dbprocess) != NO_MORE_ROWS) //开始遍历结果集合, 并且没执行一次判断一次是否还有后续数据
{
//这里添加你想要的对取出数据的操作
printf("name is %s, age is %s", name, age); //使用printf输出我们取出的name(本机变量), age(本机变量)
}
}
dbclose(dbprocess); //关闭数据库连接