2011. 5. 11. 12:11

C++Builder 2010에서 SQLite 사용하기.

일단.. 필자가 항상 하는 이야기 이지만.. SQLite 뭐 시발 별거 아니다.

SQLite의 특징

1. File로 데이터베이스를 구축하는 RDB이다.
2. 속도가 존나게 빠르다.
3. 기능이 간촐하며 강력하다.
4. 윈도우부터 리눅스, Mac에 이르러 완벽하게 호환성을 갖고 있다. (HPUnix, IBMAix는 테스트 모두 호환 되는것으로 알고 있다.)
5. 2TByte 라는 대용량 DB이다.

이정도면 뭐.. 프로그래머라면 SQLite에 대해서 아주 상식적인 지식은 꼭 지녀야 겠다는 느낌이 팍팍 들것이다.
실제로 요즘 스마트폰에 설치되어 있는 데이터베이스는 모두 SQLite라고 해도 과언이 아니다. 또한 많은 사람들이 애용하는 nateon이나 그 밖에 많은 프로그램들이 SQLite를 탑재하고 있다고 한다.

SQLite 설치

Download Page : http://www.sqlite.com/download.html

음.. 사실 설치라고 말하기 존나 민망하다. 그냥 홈페이지 가서 실행파일, Dll파일, 헤더파일만 있으면 된다. 자세한 설명에 앞서 필자의 환경은 Windows 7 // C++ Builder 2010 에서 테스트하였다.



저 위에 홈페이지 가서 빨간 박스 쳐 놓은 거 클릭해서 받아 압출을 풀면


아래와 같은 파일들이 나올 것이다.
 

 sqlite3.exe
 sqlite3.def
 sqlite3.dll
 shell.c
 sqlite3.c
 sqlite3.h
 sqlite3ext.h

그럼 sqlite3.exe 파일을 이제 C:\Windows\System32\ 로 옮기자. 이건 Path가 설정 되어있게끔 하는 것이다. 자신이 시스템의 환경변수를 조작하여 sqlite3.exe 파일이 있는 위치를 Path로 잡아줘도 상관없다.
자.. 그럼 이제 설치 완료 했고, 환경도 다 잡았다. ㅡ,.ㅡ;

SQLite 사용법

사실 이것도 존나 설명이라고 하기에는 민망하다. ㅡ,.ㅡ; 일단 필자는 dll 파일을 필요할 때마다 불러와 사용하는게 아니라 정적으로 박아 놓고 사용 할 생각이다. 그래서 Embacadero사에서 준 implib 유틸리티를 사용하여 lib 파일을 만들었다.


static library 파일 만들었으니 이제 저 파일 링크해서 쓰기만 하면 된다. 그럼 설명이 어쩌구 저쩌구 지랄 말고 바로 소스 본다.

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma comment(lib, "sqlite3.lib")
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    int Res = sqlite3_open(AnsiString(Edit1->Text).c_str(), &this->db);
    AnsiString Msg;
    if(Res) {
        Msg.sprintf("SQLite3 error code = [ %d ], message = [ %s ]",
                                          sqlite3_errcode(this->db), sqlite3_errmsg(this->db));
        Memo1->Lines->Add(Msg);
    }
    else {
        Memo1->Lines->Add("No Errors.");
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    char * eMsg;
    AnsiString SQL = "CREATE TABLE IF NOT EXISTS TestTable
                      (ID int PRIMARY KEY, Name char(20), Location char(20))"
;
    int Res = sqlite3_exec(this->db, SQL.c_str(), NULL, NULL, &eMsg);

    if(Res) {
        Memo1->Lines->Add(eMsg);
    }
    else {
        Memo1->Lines->Add("No Errors.");
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    sqlite3_close(this->db);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    int Res = 0;
    sqlite3_stmt * pStmt = NULL;

    if(StrToInt(LabeledEdit5->Text)) {
        AnsiString SQL = "Select * From TestTable Where ID = ?";
        sqlite3_prepare(this->db, SQL.c_str(), SQL.Length(), &pStmt, NULL);
        sqlite3_reset(pStmt);

        sqlite3_bind_int(pStmt, 1, StrToInt(LabeledEdit5->Text));
    }
    else {
        AnsiString SQL = "Select * From TestTable";
        sqlite3_prepare(this->db, SQL.c_str(), SQL.Length(), &pStmt, NULL);
        sqlite3_reset(pStmt);
    }

    while ((Res = sqlite3_step(pStmt)) == SQLITE_ROW) {
        int ID = sqlite3_column_int(pStmt, 0);
        const unsigned char * Name     = sqlite3_column_text(pStmt, 1);
        const unsigned char * Location = sqlite3_column_text(pStmt, 2);

        AnsiString tID;
        AnsiString tName;
        AnsiString tLoca;

        tID.sprintf("ID = %d", ID);
        tName.sprintf("Name = %s", Name);
        tLoca.sprintf("Location = %s", Location);

        Memo1->Lines->Add(tID);
        Memo1->Lines->Add(tName);
        Memo1->Lines->Add(tLoca);
    }
    sqlite3_finalize(pStmt);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
    Memo1->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
    int Res = 0;
    sqlite3_stmt * pStmt = NULL;

    sqlite3_exec(this->db, "BEGIN;", NULL, NULL, NULL);

    AnsiString SQL = "Insert into TestTable Values (?, ?, ?)";
    sqlite3_prepare(this->db, SQL.c_str(), SQL.Length(), &pStmt, NULL);
    sqlite3_reset(pStmt);

    sqlite3_bind_int(pStmt,  1, StrToInt(LabeledEdit1->Text));
    sqlite3_bind_text(pStmt, 2, AnsiString(LabeledEdit2->Text).c_str(),
                                AnsiString(LabeledEdit2->Text).Length(), SQLITE_TRANSIENT);
    sqlite3_bind_text(pStmt, 3, AnsiString(LabeledEdit3->Text).c_str(),
                                AnsiString(LabeledEdit3->Text).Length(), SQLITE_TRANSIENT);
    Res = sqlite3_step(pStmt);

    if(Res != SQLITE_DONE) {
        if(Res == SQLITE_ERROR) {
            SQL = "Update TestTable Set Name = ?, Location = ? Where ID = ?";
            sqlite3_prepare(this->db, SQL.c_str(), SQL.Length(), &pStmt, NULL);
            sqlite3_reset(pStmt);
            sqlite3_bind_text(pStmt, 1, AnsiString(LabeledEdit2->Text).c_str(),
                                    AnsiString(LabeledEdit2->Text).Length(), SQLITE_TRANSIENT);
            sqlite3_bind_text(pStmt, 2, AnsiString(LabeledEdit3->Text).c_str(),
                                    AnsiString(LabeledEdit3->Text).Length(), SQLITE_TRANSIENT);
            sqlite3_bind_int(pStmt,  3, StrToInt(LabeledEdit1->Text));
            Res = sqlite3_step(pStmt);
            Memo1->Lines->Add("No Errors.");
            sqlite3_exec(this->db, "COMMIT;", NULL, NULL, NULL);
        }
        else {
            AnsiString Msg;
            Msg.sprintf("SQLite3 error code = [ %d ], message = [ %s ]",
                                          sqlite3_errcode(this->db), sqlite3_errmsg(this->db));
            Memo1->Lines->Add(Msg);
        }
    }
    else {
        Memo1->Lines->Add("No Errors.");
        sqlite3_exec(this->db, "COMMIT;", NULL, NULL, NULL);
    }

    sqlite3_finalize(pStmt);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    int Res = 0;
    sqlite3_stmt * pStmt = NULL;

    sqlite3_exec(this->db, "BEGIN;", NULL, NULL, NULL);

    AnsiString SQL = "Delete from TestTable where ID = ?";
    sqlite3_prepare(this->db, SQL.c_str(), SQL.Length(), &pStmt, NULL);
    sqlite3_reset(pStmt);

    sqlite3_bind_int(pStmt, 1, StrToInt(LabeledEdit4->Text));
    Res = sqlite3_step(pStmt);

    if(Res != SQLITE_DONE) {
        AnsiString Msg;
        Msg.sprintf("SQLite3 error code = [ %d ], message = [ %s ]",
                                          sqlite3_errcode(this->db), sqlite3_errmsg(this->db));
        Memo1->Lines->Add(Msg);
    }
    else {
        Memo1->Lines->Add("No Errors.");
        sqlite3_exec(this->db, "COMMIT;", NULL, NULL, NULL);
    }

    sqlite3_finalize(pStmt);
}
//---------------------------------------------------------------------------


소스가 한 160줄 정도 되는데 존나 복잡해 보일 수도 있겠지만 시발 존나 쉬운거다. 간단하게 DML구문(Insert, Update, Delete 등)들과 DDL 구문 (Create Table) 한가지만 구현 해보았다. 필자는 프로그래밍 스타일 상 주석을 잘 안다는 아주 좆같은 버릇을 갖고 있다. 진짜 뭐가 뭔지 모르겠으면 댓글이나 메일 보내라. 친절하게 설명해주겠다.

필자께서 아주 친절하게 테스트 프로그램과 dll파일 db파일까지 모두 제공해주겠다.




Test 라고 되어있는 녀석이 DB 파일이다. 저 세개의 파일을 하나의 폴더에 넣어 놓고 실행파일을 실행해보면 직관적으로 무엇을 어떻게 해야 할지 알것이다. 참고로 [DB생성] 버튼이 생성과 Attach(연결)의 개념을 갖고 있기 때문에 프로그램을 실행하면 바로 한번은 눌러줘야 한다.

SQLite에 한자기 아쉬운 점이 있다면 한글에 관련 된 부분인데, ~~~~~~~16 함수들을 통해서 테이블 이름도 한글로 하고 칼럼명도 한글로 할 수 있다. 대박!

그리고 볼랜드포럼에 가면 ASQLite 라는 라이브러리를 배포하고 있는데.. 아쉽게도 C++ Builder 2010 에서는 안돌아간다. DataSet을 반환하게 해 놔서 아주 좋은 라이브러리인데 존나 아쉽다. 만약 이 라이브러리를 수정하여 C++ Builder 2010에서 돌아가게 해준다면 그 사람은 필자가 존나 싸부로 모시겠다.

아! 마지막으로 SQLite의 GUI Tool이 있다. 무료임에도 불구하고 시발 기능이 존나 강력하다.
존나 오바하면 거의 Toad 급이다. ㅋㅋㅋㅋㅋㅋㅋ 시발 Toad 급이긴 ㅋㅋㅋㅋㅋㅋ

여튼 소개한다.

SQLite Expert Personal
Download Page : http://www.sqliteexpert.com/download.html

용량이 22MB인데 다운 받는데 22분 걸렸다. 시발 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 인내와 용기를 겸한자는 홈페이지에서 다운 받아라.
사용법은 그냥 딱 보면 누구나 직관적으로 사용 할 수 있게 생겼다. ㅋㅋㅋ 그럼 시발 모두들 잘 사용해라.

'프로그래밍' 카테고리의 다른 글

Thread ( 스레드 ) ?  (2) 2011.05.30
Log 찍기  (0) 2011.05.17
Name Mangling (Name Decoration)  (0) 2011.05.03
Calling Convention ( 호출 규약 ) __cdecl, __stdcall, __fastcall  (3) 2011.05.02
extern 이라는 키워드에 대한 고찰  (3) 2011.05.02
Posted by 뿌직