什么是FreeTDS
簡單的說FreeTDS是一個程序庫,可以實現(xiàn)在Linux系統(tǒng)下訪問微軟的SQL數(shù)據(jù)庫! FreeTDS 是一個開源(如果你喜歡可以稱為自由)的程序庫,是TDS(表列數(shù)據(jù)流 )協(xié)議的再次實現(xiàn)。它可以被用在Sybase的db-lib或者ct-lib庫。它也包含一個ODBC的庫。允許許多開源的應用軟件比如Perl和PHP(或者你自己的c或C++程序)去連接到Sybase或 Microsoft SQL服務器。FreeTDS 以源碼的形式被發(fā)布,幾乎可以在任何操作系統(tǒng)上編譯。意味著Unix和類Unix系統(tǒng)(包括著名的分支如Interix和QNX),還有Win32,VMS,和OSX。
FreeTDS的安裝
1.下載freetds,點此下載 https://www.jb51.net/database/201983.html
2.將其解壓到任意目錄,進入到解壓后的文件夾里。
3.切換到root,配置: ./configure –prefix=/usr/local/freetds –with-tdsver=8.0 –enable-msdblib 解釋:–prefix為設置FreeTDS的安裝目錄,–with-tdsver是設置TDS版本, –enable-msdblib為是否允許Microsoft數(shù)據(jù)庫函數(shù)庫
4.make make install
5.配置環(huán)境變量:vim ~/.bashrc向此文件中加入: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/freetds/lib/
FreeTDS測試:
FreeTDS安裝好了,接下來就可以查看下FreeTDS狀態(tài)了;
運行./tsql -C ,在安裝目錄的bin目錄下可以找到tsql ,查看終端打印出來信息,這個-with-tdsver=7.1:
關于安裝參考
http://linux.chinaunix.net/techdoc/database/2008/10/31/1042291.shtml 或者:http://www.linuxdiyf.com/viewarticle.php?id=109086
FreeTDS的配置
freeTDS 的配置文件,F(xiàn)reeTDS也支持一個舊的配置文件interfaces,但請使用freetds.conf 除非你的環(huán)境必須使用interfaces。FreeTDS首先找freetds.conf文件如果沒有找到才去找 interfaces文件。 freetds.conf文件默認在/usr/local/freetds/etc目錄下,但是可以在configure時配置 sysconfdir選項,這個選項就是freetds.conf文件所存在的目錄。freetds.conf配置文件分為兩部分:一是[global]部分,另外一個是[dataserver]部分,其中 [dataserver]對應一個數(shù)據(jù)庫。在golbal中的設置是對全部數(shù)據(jù)庫起作用的,但在dataserver 部分的設置只對自己的數(shù)據(jù)庫起作用,并且可以覆蓋全局的設置。
例如: freetds.conf文件:
[global]
tds version = 4.2
[myserver]
host = ntbox.mydomain.com
port = 1433
[myserver2]
host = unixbox.mydomain.com
port = 4000
tds version = 5.0
這個文件中global設置所有數(shù)據(jù)庫使用tds版本為4.2,但在myserver2中使用的版本卻是5.0, 如果myserver2中沒有這一項,那就是用4.2版本的如myserver。
其配置項解釋如下:
ltds version : 指明tds協(xié)議的版本,連接數(shù)據(jù)庫時使用,如果在環(huán)境變量中沒有設置 此項,則由此配置決定,協(xié)議版本可取4.2,5.0,7.0,8.0。
lhost : 數(shù)據(jù)庫服務器的主機名或者ip地址。
lport : 數(shù)據(jù)庫服務器的監(jiān)聽端口,可以取任何有效的端口值,一般而言Sybase SQL10以前為 1433,10以上用5000,而Sybase SQLAnywhere 7是2638,Microsoft SQL server則用 1433。此配置可以被環(huán)境變量中的TDSPORT改寫。
linitial block size : 此值只能取512的倍數(shù),默認為512,指定了協(xié)議塊的最大值, 一般不要改變此默認 配置。
ldump file : 任何有效的文件名,指明了轉儲文件的路徑并且會打開日志記錄。
ldump file append: yes或者no,決定是否追加保存到dump file文件中。
ltimeout :設置處理的最大等待時間。
lconnect timeout: 設置連接的最大等待時間。
lemulate little endian: yes或者no,是否強制大端機使用小端方式與MS Server通信。
lclient charset : 任何有效的iconv字符集。默認值為ISO-8859-1,使FreeTDS使用 iconv在數(shù)據(jù)庫服務器和用戶程序之間轉換。
FreeTDS函數(shù)
1. Dbcmd和dbfcmd
函數(shù)原形: Dbcmd(DBPROCESS *proc,char * sql);
Dbcmd(DBPROCESS *proc, char * format,char *args);
功 能:該函數(shù)主要是構造sql語句,一個是帶參數(shù)的,一個不帶參數(shù)。
2. Dbsqlexec
函數(shù)原形:Dbsqlexec(DBPROCESS *proc);
功 能:該函數(shù)負責執(zhí)行你所構造的sql語句。
3. Dbresults
函數(shù)原形:Dbrerults(DBPROCESS *proc);
功 能:得到sql語句的執(zhí)行結果。返回值如果為NO_MORE_RESULTS=0,表明sql查詢?yōu)榭罩担ň褪菦]有一條滿足條件的結果),如果為(FAIL)=-1,表明查詢出錯,如果為(SUCCESS)=1,表明有結果且不為空。
4. DBROWS(全大寫)
函數(shù)原形:DBROWS(DBPROCESS *proc);
功 能:取出一行記錄的信息。
5. Dbbind
函數(shù)原形:Dbbind(DBPROCESS *proc,int colmn,
功 能:將sql查詢出來的結果綁定到一個變量。第一個參數(shù)為從數(shù)據(jù)庫那里拿的句柄,第二個參數(shù)是對應你的select語句中查詢需要的字段(注:必須是按照select順序綁定的,例如select user,password from hist1 ,如果值為1,就是綁定的user),第三個參數(shù)是綁定字段的類型,最后一個參數(shù)是綁定的變量。
6. Dbnextrow
函數(shù)原形:Dbnextrow(DBPROCESS *proc);
功 能:該函數(shù)將取出滿足sql語句的每一行,返回值為0,代表處理結束,返回值為-1出錯。
7. Dbcancel
函數(shù)原形:Dbcancel(DBPROCESS *proc);
功 能:清空上次查詢得到的數(shù)據(jù)集,如果是一個句柄的話,每次重新執(zhí)行select語句之前都要調(diào)用它清空結果,不然數(shù)據(jù)庫會報錯的。
8. Dbclose
函數(shù)原形:Dbclose(DBPROCESS *proc);
功 能:關閉句柄。當不再使用時必須關閉句柄。
9. Dbinit
函數(shù)原形:Dbinit()
功 能:初識化數(shù)據(jù)庫連接。返回值為-1出錯。
10. Dblogin
函數(shù)原形:LOGINREC *Dblogin();
DBSETLUSER(login,SOFT); //set the database user
DBSETLPWD(login,SOFTPASS);//set password
功 能:根據(jù)用戶名和密碼連接數(shù)據(jù)庫。
11.Dbcount
函數(shù)原形:Dbcount(DBPROCESS *proc);
功 能:該函數(shù)將得到sql結果集被處理的行數(shù),可以用它來判斷你的select語句是否得到正確的處理。
12.Dbopen
函數(shù)原形:DBPROCESS * Dbopen(LOGINREC *login,NULL);
功 能:返回一個操作數(shù)據(jù)庫的句柄。
另外再介紹兩個關于數(shù)據(jù)庫的出錯信息的函數(shù):
dberrhandle(int *err);
dbmsghandle(int* err);
實例代碼
#include stdio.h>
#include stdlib.h>
#include string.h>
#include unistd.h>
#include sqlfront.h> /* sqlfront.h always comes first */
#include sybdb.h> /* sybdb.h is the only other file you need */
#define SQLDBIP " " //SQL數(shù)據(jù)庫服務器IP
#define SQLDBPORT " " //SQL數(shù)據(jù)庫服務器端口
#define SQLDBNAME " " //SQL數(shù)據(jù)庫服務器數(shù)據(jù)庫名
#define SQLDBUSER " " //SQL數(shù)據(jù)庫服務器數(shù)據(jù)庫用戶名
#define SQLDBPASSWD " " //SQL數(shù)據(jù)庫服務器用戶密碼
#define SQLDBSERVER SQLDBIP":"SQLDBPORT
#define DBSQLCMD "select * from yancao"
int main(int argc, char *argv[])
{
int i, ch;
LOGINREC *login; //描述客戶端的結構體,在連接時被傳遞到服務器.
DBPROCESS *dbproc; //描述連接的結構體,被dbopen()函數(shù)返回
RETCODE erc; //庫函數(shù)中最普遍的返回類型.
/*************************************************************/
//在開始調(diào)用本庫函數(shù)前常常要先調(diào)用dbinit()函數(shù)
if (dbinit() == FAIL) {
fprintf(stderr, "%s:%d: dbinit() failed\n",argv[0], __LINE__);
exit(1);
}
//dblogin()函數(shù)申請 LOGINREC 結構體,此結構體被傳遞給dbopen()函數(shù),用來創(chuàng)建一個連接。
//雖然基本上不會調(diào)用失敗,但是檢查它!.
if ((login = dblogin()) == NULL) {
fprintf(stderr, "%s:%d: unable to allocate login structure\n",argv[0],__LINE__);
exit(1);
}
//LOGINREC結構體不能被直接訪問,要通過以下宏設置,下面設置兩個必不可少的域
DBSETLUSER(login, SQLDBUSER);
DBSETLPWD(login, SQLDBPASSWD);
/*************************************************************/
//dbopen()與服務器建立一個連接. 傳遞 LOGINREC 指針和服務器名字
if ((dbproc = dbopen(login, SQLDBSERVER)) == NULL) {
fprintf(stderr, "%s:%d: unable to connect to %s as %s\n",
argv[0], __LINE__,
SQLDBSERVER, SQLDBUSER);
exit(1);
}
// 可以調(diào)用dbuser()函數(shù)選擇我們使用的數(shù)據(jù)庫名,可以省略,省略后使用用戶默認數(shù)據(jù)庫.
if (SQLDBNAME (erc = dbuse(dbproc, SQLDBNAME)) == FAIL) {
fprintf(stderr, "%s:%d: unable to use to database %s\n",
argv[0], __LINE__, SQLDBNAME);
exit(1);
}
/*************************************************************/
dbcmd(dbproc, DBSQLCMD);//將SQL語句填充到命令緩沖區(qū)
printf("\n");
if ((erc = dbsqlexec(dbproc)) == FAIL) {
fprintf(stderr, "%s:%d: dbsqlexec() failed\n", argv[0], __LINE__);
exit(1); //等待服務器執(zhí)行SQL語句,等待時間取決于查詢的復雜度。
}
/*************************************************************/
//在調(diào)用dbsqlexec()、dbsqlok()、dbrpcsend()返回成功之后調(diào)用dbresults()函數(shù)
printf("then fetch results:\n");
int count = 0;
while ((erc = dbresults(dbproc)) != NO_MORE_RESULTS) {
struct col { //保存列的所有信息
char *name; //列名字
char *buffer; //存放列數(shù)據(jù)指針
int type, size, status;
} *columns, *pcol;
int ncols;
int row_code;
if (erc == FAIL) {
fprintf(stderr, "%s:%d: dbresults failed\n",
argv[0], __LINE__);
exit(1);
}
ncols = dbnumcols(dbproc);//返回執(zhí)行結果的列數(shù)目
if ((columns = calloc(ncols, sizeof(struct col))) == NULL) {
perror(NULL);
exit(1);
}
/* read metadata and bind. */
for (pcol = columns; pcol - columns ncols; pcol++) {
int c = pcol - columns + 1;
pcol->name = dbcolname(dbproc, c); //返回指定列的列名
pcol->type = dbcoltype(dbproc, c);
pcol->size = dbcollen(dbproc, c);
printf("%*s(%d)", 20, pcol->name, pcol->size);
if ((pcol->buffer = calloc(1, 20)) == NULL) {
perror(NULL);
exit(1);
}
erc = dbbind(dbproc, c, NTBSTRINGBIND, 20, (BYTE*)pcol->buffer);
if (erc == FAIL) {
fprintf(stderr, "%s:%d: dbbind(%d) failed\n",
argv[0], __LINE__, c);
exit(1);
}
erc = dbnullbind(dbproc, c, pcol->status); //(5)
if (erc == FAIL) {
fprintf(stderr, "%s:%d: dbnullbind(%d) failed\n",
argv[0], __LINE__, c);
exit(1);
}
}
printf("\n");
/* 打印數(shù)據(jù) */
while ((row_code = dbnextrow(dbproc)) != NO_MORE_ROWS) {//讀取行數(shù)據(jù)
switch (row_code) {
case REG_ROW:
for (pcol=columns; pcol - columns ncols; pcol++) {
char *buffer = pcol->status == -1?
"null" : pcol->buffer;
printf("%*s ", 20, buffer);
}
printf("\n"); break;
case BUF_FULL: break;
case FAIL:
fprintf(stderr, "%s:%d: dbresults failed\n",
argv[0], __LINE__);
exit(1); break;
default: // (7)
printf("data for computeid %d ignored\n", row_code);
}
}
/* free metadata and data buffers */
for (pcol=columns; pcol - columns ncols; pcol++) {
free(pcol->buffer);
}
free(columns);
if (DBCOUNT(dbproc) > -1) /* 得到SQL語句影響的行數(shù) */
fprintf(stderr, "%d rows affected\n", DBCOUNT(dbproc))
}
dbclose(dbproc);
dbexit();
}