본문 바로가기

UNIX_LINUX_C_C++

Linux에서 MS-SQL에 접속하기 - FreeTDS

[펌] http://mizzim.com/386

FreeTDS 사용하기

반갑습니다. 이글은 FreeTDS 에 대해서 김명화님께서 작성해 주신 글입니다. 실무자 입장에서 FreeTDS 를 이용하여 어떻게 리눅스에서 MS SQL 로 접속할 것인가에 대해 적어 놓았으므로 많은 도움이 될 것으로 생각됩니다.

================

1. FreeTDS 란 무엇인가.

1) 등장배경

2) 개발 역사

2. FreeTDS로 무엇을 할 수 있는가?

3. 설치하기

4. FreeTDS DB-lib를 이용한 C 프로그램 개발하기

5. 발전했으면 하는 방향

6. 결론

3. 설치하기

FreeTDS 패키지나 RPM파일은 iBiblio 나 그 미러사이트에서 구하실 수 있습니다.

ftp://ibiblio.org/pub/Linux/ALPHA/freetds/freetds-0.52.tgz

ftp://ibiblio.org/pub/Linux/ALPHA/freetds/freetds-0.52-1.i386.rpm

ftp://ibiblio.org/pub/Linux/ALPHA/freetds/freetds-devel-0.52-1.i386.rpm

FreeTDS를 설치하는 방법은 2가지가 있습니다.

- rpm 설치

# rpm –Uvh freetds rpm 파일

- tar 압축파일 직접 설치

컴파일과 설치문서가 DSN에 올려져 있지만 간략하게나마 짚고 넘어가죠.

rpm 설치는 직접설치 과정을 생략한 후, 설치된 디렉토리 아래서 작업을 시작하면 되겠죠.

(rpm이 나온 이상 직접 설치를 할 이유는 별로 없겠지만 저는 설치를 다 한 후에 rpm을 찾았답니다. --)

시스템 사양 : Alzza Linux 6.2 (커널 2.2.16-3)

설치 FreeTDS버전 : 0.51

설치 기본 디렉토리 : /usr/local/freetds

1. freetds-0.5x.tgz을 다운받습니다.

2. /usr/local 로 가져옵니다.

3. # tar xvfz freetds-0.5x.tgz 하면 freetds 디렉토리가 생기면서 깔립니다.

a) # ./configure 실행합니다.

b) # make ( FreeTDS package를 compile합니다)

c) # make install (Doc파일과 소스파일들 설치합니다)

a)에서 c)까지의 과정은 configure 스크립트와 configure 스크립트를 만들어주는

autoconf, automake 등의 GNU 스타일의 소스 패키지 만들기에 대한 글을 참조하시면

자세히 알 수 있습니다.

d) /usr/local/freetds/ 의 interfaces 와 PWD 파일을 찾아봅시다.

  PWD 파일 : MS-SQL 서버로 접속하기 위한 user, pwd, database명, 서버명을              명시해놓는 txt파일인데, 굳이 사용하지 않아도 좋습니다.              프로그램 안에서 설정해도 되니까요. 

< PWD 파일 들여다보기 >

# vi PWD

-----------------------------------------------------------------------------

This file was taken from DBD::Sybase :-) It is used by 'make test' to test

# the installation

UID=testdbuser (MS-SQL서버로 접속할 사용자ID)

PWD=비밀번호

SRV=myDBserver (interfaces file에 명시해놓을(은) MS-SQL서버의 이름)

DB=testDB (사용할 데이터베이스명)

-----------------------------------------------------------------------------

< interfaces파일 들여다보기 & MS-SQL서버 지정 >

-----------------------------------------------------------------------------

JDBC        query tcp tds5.0 192.138.151.39 4444        master tcp tds5.0 192.138.151.39 4444 myserver        query tcp ether 127.0.0.1 4000        master tcp ether 127.0.0.1 4000 myserver2        query tcp ether 127.0.0.1 4001        master tcp ether 127.0.0.1 4001myDBserver (이것을 MS-SQL서버명으로 합시다)        query tcp ether MS-SQL서버IP 1433       master tcp ether MS-SQL서버IP 1433   

MS-SQL서버로 접속할 포트는 보통 1433번으로 지정됩니다.

서버담당자가 포트번호를 바꿀 경우는 접속이 안될테니, 그때마다 상의하시구요.

-----------------------------------------------------------------------------

e) 프로그램을 하기위한 환경설정

FreeTDS를 사용하려면 설정해주어야하는 환경변수가 있습니다.

환경변수명은 SYBASE로, FreeTDS library의 위치를 지정해주어야 합니다.

SYBASE라는 이름 때문에 MS-SQL을 사용하는 것이 아니라,

sybase를 사용하기 위한 설치인가? 하고 혼동할 수 있는데,

MS-SQL의 모태가 SYBASE니까, 그렇게 이해를 하실 수 있겠지요?

로그인할 때 실행되는 shell에다 지정해놓으면 되겠습니다.

bash를 사용할 때, root유저인 경우는 .bash_profile, 일반 유저는 .bashrc

제 .bash_profile을 오픈하겠습니다.

-------------------------------------------------------------------------------------------------------------- # .bash_profile # Get the aliases and functionsif [ -f ~/.bashrc ]; then        . ~/.bashrcfi # User specific environment and startup programs PATH=$PATH:$HOME/bin:/home/bonus/pgm/say:ENV=$HOME/.bashrcUSERNAME="root"export USERNAME ENV PATH#SYBASE 환경변수와 freetds library위치를 지정해놓습니다. SYBASE=/usr/local/freetdsLD_LIBRARY_PATH=$:$SYBASE/libexport SYBASE LD_LIBRARY_PATH# C_INCLUDE_PATH환경변수와 사용자 정의 헤더파일의 위치 지정합니다.# 지정하지 않을 경우엔 프로그램 컴파일 시 make파일 안에 -I로 헤더위치를# 포함시켜주면 됩니다.export C_INCLUDE_PATH=$:$SYBASE/include mesg n-----------------------------------------------------------------------------

저장한 후 재로긴하면 설정이 됩니다.

f) 샘플 source 위치

/usr/local/freetds/src/dblib, ctlib, tds 등의 각 라이브러리의 unittests directory

/usr/local/freetds/src/dblib/unittests/sample program

t0001.c ~ t0020.c의 샘플 소스와 Makefile이 있습니다.

common.c, pwd.c는 다른 프로그램 사용할때도 포함해서 컴파일하시면 됩니다.

common.c : db-lib 에러 발생시 에러정보, 에러 로그를 보여줍니다.

pwd.c : db-lib 로그인 시 필요한 정보(PWD파일)를 불러옵니다.

# make 실행파일명으로 컴파일 해봅니다.

4. FreeTDS DB-lib를 이용한 C 프로그램 개발하기

1) DBlibrary란?

TDS(Tabular Data Stream)은 데이터베이스로부터 DBLibrary를 이용해 데이터를 Fetch해 올 수 있도록 해주는 Method입니다.

DBLibrary는 사이베이스로부터 MS로 상속되었고, SQL서버 데이터베이스에서 상호작용을 하는 client 인터페이스의 하나로써, C언어로 데이터베이스를 수행 가능하게 하는 명령어와 함수Set입니다.

2) DBLibrary API Reference

MS-SQL의 DBLibrary를 한번도 사용해보지 못했다고 해서 겁낼 필요는 없습니다. 아주 기초적인 함수 몇 개만 써보면 금방 익숙해지니까요. DBlibrary 함수들은 비주얼 스튜디오에서 참조하실 수 있고, 없으신 분들은

http://ns.ddart.pe.kr/mssql/sql2000/html/dblibc/를 보시면 됩니다.

이것을 보시면 궁금하실 함수들의 리스트와 그에 따른 간략한 예제들, 자세한 설명이 모두 다 나와있기 때문에 걱정없이 프로그램하시면 됩니다.

개별적인 함수에 관한 설명을 붙이지 않아도 되겠지요.

테스트할 디렉토리에서 프로그램 해봅시다.

3) 소스 컴파일 Makefile 만들기

 간단하게 작성한 makefile -----------------------------------------------------------------------------AR_PATH  = /usr/local/freetds/lib/libsybdb.aOBJ = sybase.o common.o pwd.o FLAGS= -c -O .c.o:        $ $ $< sybase: $ $        $ -O -o sybase $ $ -----------------------------------------------------------------------------홈디렉토리의 .bashrc 안에 C_INCLUDE_PATH 지정을 안했으면, 아래와 같이 합니다.-----------------------------------------------------------------------------AR_PATH  = /usr/local/freetds/lib/libsybdb.aHEADERDIR = /usr/local/freetds/includeOBJ = sybase.o common.o pwd.o FLAGS= -c -O -I$.c.o:        $ $ $< sybase: $ $        $ -O -o sybase $ $ -----------------------------------------------------------------------------[b]4) 프로그램에 앞선 DBLibrary DataType 보기[/b]다음은 DBLibrary에서 정의하고 있는 데이터타입입니다.(물론 이 정의도 위의 URL에서 찾아보실 수 있습니다.)예제 프로그램에서도 쓰여있지만, 비교해보면 특별한 것은 아니죠.일반적인 C 데이터타입을 쓰셔도 무방합니다.typedef char            DBCHAR;        // char and texttypedef unsigned char   DBBINARY;      // binary and imagetypedef unsigned char   DBTINYINT;     // 1-byte tinyinttypedef short           DBSMALLINT;    // 2-byte smallinttypedef unsigned short  DBUSMALLINT;   // Unsigned 2-byte integertypedef long            DBINT;         // 4-byte inttypedef float           DBFLT4;        // 4-byte realtypedef double          DBFLT8;        // 8-byte floattypedef unsigned char   DBBIT;         // bittypedef unsigned char   DBBOOL;        // Booleantypedef long            DBMONEY4;      // 4-byte smallmoneytypedef struct dbmoney       // 8-byte money{    DBINT mnyhigh;    ULONG mnylow;} DBMONEY;typedef struct dbdatetime4   // 4-byte smalldatetime{    USHORT numdays;          // Days since Jan 1, 1900    USHORT nummins;          // Minutes since midnight} DBDATETIM4;typedef struct dbdatetime    // 8-byte datetime{    DBINT dtdays;            // Days since Jan 1, 1900    ULONG dttime;            // 300ths of a second since midnight} DBDATETIME;#define MAXNUMERICLEN 16typedef struct dbnumeric     // Numeric (and decimal){    BYTE precision;          // Precision    BYTE scale;              // Scale    BYTE sign;               // 1 = Positive, 0 = Negative    BYTE val[MAXNUMERICLEN]; // Padded little-endian value} DBNUMERIC;typedef DBNUMERIC DBDECIMAL; // Decimal#define DBMAXCHAR 256typedef struct dbvarychar          // Pascal-type string{    DBSMALLINT  len;               // Character count    DBCHAR      str[DBMAXCHAR];    // Nonterminated string} DBVARYCHAR;typedef struct dbvarybin           // Pascal-type byte array{    DBSMALLINT  len;               // Byte count    BYTE        array[DBMAXCHAR];  // Nonterminated array} DBVARYBIN;----------------------------------------------------------------5) MS-SQL서버에 table 만들기 -----------------------------------------------------------   TABLE 명 : test_user   컬럼명      :  userid(10) 	         username(20)	         userage 	bit	         gender 	Tinyint -----------------------------------------------------------아래는 간단한 C 예제 프로그램입니다.program명 :  sybase.c#include // 프로그램에서 쓰이는 특정변수, value들이  //sybfront.h, sybdb.h에 정의되어 있습니다. #include #include #include "common.h"char	sql_buf[1024];// 데이터베이스에서 가져온 컬럼을 아래 structure에 담아보죠.struct USER_STAT {	char	uid[10];	char	user_name[20];	u_char	age;	u_char	gender;}user_stat;int main(){       LOGINREC *login; /* login information */       DBPROCESS *dbproc;        DBINT ageint;       char id[10],name[10];       u_char	gender;	int	id_length, name_length;       // 혹시라도 SYBASE 환경변수를 인식을 못하는 경우가 있다면, 아래와 같이       // 써주세요.  SYBASE환경변수 인식을 못하면 데이터를 못가져오거나        // 이상하게 가져오지요.         // .bashrc 나 .profile 등에 제대로 설정해놓았으면 문제는 없습니다만.. 	   putenv("SYBASE=/usr/local/freetds");	   putenv("TDSVER=70");       // 한글입력,갱신이 있을 경우는 버전을 4.2로 해주세요.       // 7.0은 한글처리가 안됩니다.        // putenv("TDSVER=42");           dbinit();    /* db-lib를 초기화한다 */       // err-msg,msg handler를 등록. common.c 에 있는 함수.       // 에러메시지 안봐도 알게될 정도가 되면 아래 두 줄 막으시구요.        dberrhandle( syb_err_handler );        dbmsghandle( syb_msg_handler );              login = dblogin();               // login record를 가져온다        // sample디렉토리에 있는 pwd.c의 read_login_info()를 사용해도 되고,        // 아래대로 직접 써도 되고요. read_login_info()는 PWD 파일을 읽어       // 들이는 것이죠.                DBSETLPWD(login,"패스워드");             /* login pass word set     */       DBSETLUSER(login,"DB유저ID");       /* login id set            */       // 아래 두줄은 안써도 상관은 없죠. 뭐. ^^       DBSETLAPP(login,"sybase"); //SQL server쪽에 넘겨줄 어플리케이션명        DBSETLHOST(login,"Linux"); //SQL server쪽에 넘겨줄 호스트명     // MS-SQL서버IP와 PORT 설정해놓은 interfaces file의 server명(myDBserver)     // 을 쓰는겁니다. 자,,, DB오픈합니다.       dbproc = dbopen(login, "myDBserver");     // 이제부턴 데이터베이스내 테이블 검색을 하고, 입력을 하고,      // 갱신을 하고, 지우고... 하는 것들의 시작입니다.     // dbcmd -> 커맨드 입력받기.	dbcmd(dbproc,"select userid,username,userage,gender                            from test_user where userid = 'bonus'");    //아래와 같이 해도 무방합니다. 버퍼에 카피해서 버퍼내용을 실행하게끔.     // 명령이 길면, 아래처럼 나눠서 쓰시고, 명령어 사이의 공백을 주의하시고.    // sprintf(sql_buf,"select userid,username,userage,gender from test_user"       " where userid = 'bonus'"); 	// dbcmd(dbproc,sql_buf);    dbcmd(dbproc,"update test_user set username = '뽀나스'"           " where userid = 'bonus'");    dbcmd(dbproc,"delete from test_user where gender = 1");    // dbsqlexec -> dbcmd에서 입력받은 명령어들을 SQL서버로 전달합니다.    // dbsqlexec이전에 쓰여진 dbcmd 순서대로 실행합니다.      // 위의 경우 select - update - delete 를 전달합니다.	     dbsqlexec(dbproc);     // dbresults -> 명령의 결과를 가져오기위해 준비합니다.     dbresults(dbproc);	      //dbbind -> select한 컬럼을 프로그램안의 변수에 담습니다.      // argument 0 : dbprocess     // argument 1 : select하는 컬럼의 순서(1부터 시작합니다.)     // argument 2 : 데이터타입 (참조표를 보면 쉽게 알 수 있습니다)     // argument 3 : 컬럼 담을 변수의 length. 0으로 설정해놓으면      //              변수크기만큼 쓸 수 있습니다.            dbbind(dbproc,1,STRINGBIND,0,id);     dbbind(dbproc,2,STRINGBIND,0,name);     dbbind(dbproc,3,INTBIND,0,(BYTE *) &testnum);     dbbind(dbproc,4,CHARBIND,0,(BYTE *) &gender);    // dbnextrow -> 검색결과물을 가져옵니다.     while(dbnextrow(dbproc) != NO_MORE_ROWS) {     printf(" Result : ID : %s name : %s  age : %d  gender :%c \n",id,name,ageint,gender);	    }    //  structure에 char형의 데이터를 담을 때 빈번하게 발생하는 일이지만,     //  같은 char형의 데이터가 뒷단에 붙여질 수 있으니,     // char형의 데이터는 컬럼의 길이만큼 strcpy하지말고, 데이터의 길이만큼 strcpy해야    // 제대로 보여집니다.  또한, 여백, 캐리지리턴값은 모두 null로 바꿉니다. 	id_length = strlen(id);        strncpy(user_stat.uid , id, id_length);   	last_space_kill(user_stat.uid); 	name_length = strlen(name);        strncpy(user_stat.username ,name,name_length);   	last_space_kill(user_stat.uid);        user_stat.age = ageint;        user_stat.gender = gender;     // DB 접속 종료합니다.       dbexit();     }last_space_kill(cp)char    *cp;{        int     i, n;        n = strlen(cp);         for (i=n-1 ; i>=0; i--) {                if (cp[i ] == ' ' || cp[i ] == '\t'                           || cp[i ] == '\n' || cp[i ] == '\r' )                        cp[i ] = '';                else                        break;        }}   5. 발전했으면 하는 방향  이 글을 쓰는 중에 FreeTDS-0.52버전이 나온 것을 알고, 매우 반가왔습니다.인스톨해서 테스트해보기 전이니 무엇이 달라진지 확인해보진 못했지만, 제가 0.51버전을 쓰면서 나아졌으면 좋겠다하는 일부분을 수용했겠지요.대략적으로, 이러한 내용들이 보이는군요. . Major enhancements to the ODBC driver allowing it to work with the unixODBC    and iODBC driver managers as well as working with PHP and Perl ODBC interfaces.ODBC 드라이버 부분에서 가장 향상된 것은 PHP 와 Perl ODBC 와동작할 뿐만 아니라 unixODBC 와 iODBC 와도 잘 동작한다는 것이다.. New configuration file format for finer grained control. 보다 섬세한 control 이 가능한 새로운 configuration 파일 포맷의 지원The older 'interfaces' format is retained as a fallback for Sybase compatibility. 기존의 인터페이스 포맷은 사이베이스와의 호환을 위한 대체로 남겨둠. . Preliminary connection pooling code.    Connection 을 pooling을 이용하여 미리 조절가능 (일종의 캐슁기능). Better  documentation. 좀더 나아진 문서.  . FreeTDS is now 64bit clean. 64bit 처리에 대한 문제점 해결.. Added support for nullable bit types under TDS 7.0TDS 7.0 하에서 null bit-type지원을 추가.. Many bug fixes.대부분의 버그 수정.

6. 결론

리눅스에서 MS-SQL을 쓸 일이 제겐 없을거라고 생각했습니다만, 올해 그런 경우를 당했습니다. 꼭 하지않으면 안될 일이 생길 때, 그 방법론을 모를 때의 난감함. 마침내 이곳 DSN에서 FreeTDS가 MS-SQL을 지원한다는 사실을 알았고, 안도했었지요.

MS의 나날히 화려해지는 제품들을 보면 FreeTDS로 핸들링할 수 없는, 한계시점이 오지 않을까하는 불안감이 생기기도 하는데, 꾸준한 FreeTDS의 개발이 이루어지고, FreeTDS사용자들이 증가한다면, MS에서도 DBLibrary의 지원을 쉽게 놓지는 않을 것 같다는 생각이 듭니다.

무엇보다도 시간이 없는 바쁘고도 게으른 프로그래머들에게 도움이 될만한 (한글)자료들이 많아졌으면 하는 게 저의 가장 큰 바램입니다.