您的位置:首页 > 运维架构 > Linux

Linux下使用C/C++访问数据库——SQL Server篇

2017-07-12 16:35 411 查看
转载自 commandos 的BLOG:http://commandos.blog.51cto.com/154976/136829/

 

在Linux下连接MSSQL是一件很痛苦的事,因为微软同志没有提供任何接口给开发人员,大约他们认为要用MSSQL的,只可能是windows的操作系统。还好,MSSQL是从Sybase衍生出来的,有一些哥们做了一些Sybase的Linux下的连接库,这些连接库同时也能支持MSSQL,FreeTDS就是这样的一个东东。

这篇文章的受用读者,我想是那些希望在Linux或Unix下编写C或C++程序来连接MSSQL2000的兄弟们,因为我就是这样的。同时,那些写PHP的哥们也可以参考一下,当然如果你是用PHP的,你恐怕还要知道APACHE以及PHP脚本的安装,或者关于PHP自定义Module的开发,可以参考我以前写的一篇Blog(PHP5自定义Module开发)。

下面开始我们的探索之旅:

一、相关软件

首先我们需要FreeTDS的安装包,可以在这个地址下载到:http://ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-stable.tgz
现在的最新版是0.82
其次就是大家需要自己搭建C++的开发环境了。

二、软件安装、配置

# tar zxvf freetds-stable.tgz(解压)
# ./configure --prefix=/usr/local/freetds \(指定FreeTDS安装路径) 

     --with-tdsver=8.0 --enable-msdblib (设置TDS版本,支持SQL Server 2000)
# make
# make install
将freetds的库文件所在路径配置到LD_LIBRARY_PATH参数中: 

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/freetds/lib/: 

这么作的目的是为了避免加载FreeTds库文件加载不上的情况。

三、程序开发

不多说了,还是直接上代码:

/*    

* SyBaseManager.h    

*    

*    Created .: Feb 18, 2009    

*            Author: Steven Wee    

*/    

#ifndef SYBASEMANAGER_H_    

#define SYBASEMANAGER_H_    

#include "../Common/CheckStringTools.h"    

#include <string>    

#include <vector>    

#include <iostream>    

#include <assert.h>    

#include <errno.h>    

#include <stdlib.h>    

#include <string.h>    

#include <sybfront.h>    

#include <sybdb.h>    

using namespace std;    

class SybaseManager    

{    

public:    

        SybaseManager(std::string hosts, std::string userName, std::string password, std::string dbName, unsigned int port);    

        ~SybaseManager();    

        /*    

         * Init SQL Server    

         * @param hosts:         Host IP address    

         * @param userName:        Login UserName    

         * @param password:        Login Password    

         * @param dbName:        Database Name    

         * @param port:                Host listen port number    

         */    

        void initConnection();    

        /*    

         * Making query from database    

         * @param mysql:        MySQL Object    

         * @param sql:                Running SQL command    

         */    

        bool runSQLCommand(std::string sql);    

        /**    

         * Destroy MySQL object    

         * @param mysql                MySQL object    

         */    

        void destroyConnection();    

        bool getConnectionStatus();    

        vector<vector<string> > getResult();    

protected:    

        void setUserName(std::string userName);    

        void setHosts(std::string hosts);    

        void setPassword(std::string password);    

        void setDBName(std::string dbName);    

        void setPort(unsigned int port);    

private:    

        bool IsConnected;    

        DBPROCESS *dbProcess;    

        vector< vector<string> > resultList;    

        unsigned int DEFAULTPORT;    

        char * HOSTS;    

        char * USERNAME;    

        char * PASSWORD;    

        char * DBNAME;    

};    

#endif /* SYBASEMANAGER_H_ */ 

/*    

* SyBaseManager.cpp    

*    

*    Created .: Feb 18, 2009    

*            Author: Steven Wee    

*/    

#include "SybaseManager.h"    

SybaseManager::SybaseManager(std::string hosts, std::string userName, std::string password, std::string dbName, unsigned int port)    

{    

        IsConnected = false;    

        this ->setHosts(hosts);    

        this ->setUserName(userName);    

        this ->setPassword(password);    

        this ->setDBName(dbName);    

        this ->setPort(port);    

}    

SybaseManager::~SybaseManager()    

{    

        destroyConnection();    

}    

void SybaseManager::setDBName(string dbName)    

{    

        if ( dbName.empty() )    

        {    

                std::cout << "DBName is null! Used default value: master" << std::endl;    

                this ->DBNAME = new char[5];    

                strcpy(this ->DBNAME, "master");    

        }    

        else    

        {    

                this ->DBNAME = new char[dbName.length()];    

                strcpy(this ->DBNAME, dbName.c_str());    

        }    

}    

void SybaseManager::setHosts(string hosts)    

{    

        if ( hosts.empty() )    

        {    

                std::cout << "Hosts is null! Used default value: localhost" << std::endl;    

                this ->HOSTS = new char[9];    

                strcpy(this ->HOSTS, "localhost");    

        }    

        else    

        {    

                this ->HOSTS = new char[hosts.length()];    

                strcpy(this ->HOSTS, hosts.c_str());    

        }    

}    

void SybaseManager::setPassword(string password)    

{    

        if ( password.empty() )    

        {    

                std::cout << "Password is null! Used default value: " << std::endl;    

                this ->PASSWORD = new char[1];    

                strcpy(this ->PASSWORD, "");    

        }    

        else    

        {    

                this ->PASSWORD = new char[password.length()];    

                strcpy(this ->PASSWORD, password.c_str());    

        }    

}    

void SybaseManager::setPort(unsigned int port)    

{    

        if ( port )    

        {    

                std::cout << "Port number is null! Used default value: 0" << std::endl;    

                this ->DEFAULTPORT = 0;    

        }    

        else    

        {    

                this ->DEFAULTPORT = port;    

        }    

}    

void SybaseManager::setUserName(string userName)    

{    

        if ( userName.empty() )    

        {    

                std::cout << "UserName is null! Used default value: sa" << std::endl;    

                this ->USERNAME = new char[4];    

                strcpy(this ->USERNAME, "sa");    

        }    

        else    

        {    

                this ->USERNAME = new char[userName.length()];    

                strcpy(this ->USERNAME, userName.c_str());    

        }    

}    

void SybaseManager::initConnection()    

{    

        string Charset = "UTF-8";    

        dbinit();    

        LOGINREC *loginREC = dblogin();    

        DBSETLUSER(loginREC, this ->USERNAME);    

        DBSETLPWD(loginREC, this ->PASSWORD);    

        DBSETLCHARSET(loginREC, Charset.c_str());    

        dbProcess = dbopen(loginREC, this ->HOSTS);    

        if ( dbProcess == FAIL )    

        {    

                std::cout << "Connect to SQL Server failed!" << std::endl;    

        }    

        if ( dbuse( dbProcess, this ->DBNAME ) == FAIL )    

        {    

                std::cout << "Use table failed!" << std::endl;    

        }    

}    

bool SybaseManager::runSQLCommand( string sql )    

{    

        dbcmd(dbProcess, sql.c_str());    

        if ( dbsqlexec(dbProcess) == FAIL )    

        {    

                std::cout << "Query from database failed!" << std::endl;    

        }    

        DBINT result_code;    

        vector<string> objectValue;    

        StringTools stringTools;    

        sql = stringTools.filterString(sql);    

        while ( (result_code = dbresults(dbProcess)) != NO_MORE_RESULTS )    

        {    

                struct Column    

                {    

                        char* colName;    

                        char* colBuffer;    

                        int colType, colSize, colStatus;    

                } *columns, *pCol;    

                int nColumns;    

                int rowNo;    

                if ( result_code == SUCCEED )    

                {    

                        nColumns = dbnumcols(dbProcess);    

                        if ( (columns = (Column*)calloc(nColumns, sizeof(struct Column))) == NULL )    

                        {    

                                std::cout << "Error at bind data" << std::endl;    

                                return false;    

                        }    

                        for ( pCol = columns; pCol - columns < nColumns; pCol++ )    

                        {    

                                int colNo = pCol - columns + 1;    

                                pCol ->colName = dbcolname(dbProcess, colNo);    

                                pCol ->colType = dbcoltype(dbProcess, colNo);    

                                pCol ->colSize = dbcollen(dbProcess, colNo);    

                                if ( SYBCHAR != pCol ->colType )    

                                {    

                                        pCol ->colSize = dbwillconvert(pCol ->colType, SYBCHAR);    

                                }    

                                if ( (pCol ->colBuffer = (char*)calloc(1, pCol ->colSize + 1)) == NULL )    

                                {    

                                        std::cout << "Check column buffer error!" << std::endl;    

                                        return false;    

                                }    

                                if ( dbbind(dbProcess, colNo, STRINGBIND, pCol ->colSize + 1, (BYTE*)pCol ->colBuffer) == FAIL )    

                                {    

                                        std::cout << "Running dbbind() error!" << std::endl;    

                                        return false;    

                                }    

                                if ( dbnullbind(dbProcess, colNo, &pCol ->colStatus) == FAIL )    

                                {    

                                        std::cout << "Running dbnullbind() error!" << std::endl;    

                                        return false;    

                                }    

                        }    

                        while ( (rowNo = dbnextrow(dbProcess)) != NO_MORE_ROWS )    

                        {    

                                objectValue.clear();    

                                switch ( rowNo )    

                                {    

                                case REG_ROW:    

                                        for ( pCol = columns; pCol - columns < nColumns; pCol++ )    

                                        {    

                                                const char* columnBuffer = pCol ->colStatus == -1 ? "NULL" : pCol ->colBuffer;    

                                                objectValue.push_back(stringTools.Trim(columnBuffer));        //        std::cout << columnBuffer << std::endl;    

                                        }    

                                        break;    

                                case BUF_FULL:    

                                        assert( rowNo != BUF_FULL );    

                                        break;    

                                case FAIL:    

                                        std::cout << "Get result error!" << std::endl;    

                                        break;    

                                default:    

                                        std::cout << "Get result ignore, row number:" << rowNo << std::endl;    

                                }    

                                this ->resultList.push_back(objectValue);    

                        }    

                        for ( pCol = columns; pCol - columns < nColumns; pCol++ )    

                        {    

                                free( pCol ->colBuffer );    

                        }    

                        free( columns );    

                        /*    

                        if ( DBCOUNT(dbProcess) > -1 )    

                        {    

                                std::cout << "Affected rows:" << DBCOUNT(dbProcess) << std::endl;    

                        }    

                        */    

                        if ( dbhasretstat(dbProcess) == TRUE )    

                        {    

                                std::cout << "Procedure returned " << dbhasretstat(dbProcess) << std::endl;    

                        }    

                }    

        }    

        return true;    

}    

void SybaseManager::destroyConnection()    

{    

        dbclose(dbProcess);    

}    

bool SybaseManager::getConnectionStatus()    

{    

        return IsConnected;    

}    

vector< vector<string> > SybaseManager::getResult()    

{    

        return this ->resultList;    



 

四、修改建议

本人在以后的完善中,打算把runSQLCommand(char * sql)函数分解成两个或者三个函数,分别执行select和insert等语句。
在程序中,我并没有强制要求参数必须为const,可能会出现一些安全问题。
本文仅起抛砖引玉的作用,希望有高手可以指点我程序中的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息