본문 바로가기

DBMS

SQLite 설명 및 예제 코드


= SQLite =
== 장점 ==

* ACID(Atomic, Consistent, Isolate, Durable) 보증 (시스템오류나 전원이 갑자기 꺼진 경우에도)
* Setting 절차없이 그냥 바로 사용할 수 있다.
* SQL92의 대부분을 지원한다. 다음 목록은 지원하지 않는다.
  - FOREIGN KEY constraints
  - Complete trigger support
  - Complete ALTER TABLE support
  - Nested transactions (1개의 Active Tranjection만을 지원)
  - RIGHT and FULL OUTER JOIN (Left Join은 지원)
  - Writing to VIEWs (View는 Read Only이다)
  - GRANT and REVOKE (client/server 모델이 아니라 지원할 수 없다)
* 단일 파일에 데이터베이스의 모든것을 포함한다. (백업이나 이전하고 싶으면 파일 하나만 이동하면 된다)
* byte order에 관계없이 데이터 파일의 공유가 가능 (Mac,Intel,PowerPC등등에서도 그냥 카피만 하면 된다)
* 2테라바이트 (2^41)크기의 데이터 파일 생성지원
* String이나 BLOB 의 길이 한계는 메모리에 의해서만 영향받는다
* 효율적인 메모리 사용 : 모든 설정을 다 포함하여 250KB, 기본기능만 포함하면 150KB이내
* 많은 일반적인 명령을 실행하는데 PostgreSql과 Mysql보다 최소 2배이상 명령에 따라서 10-20배 이상 빠르다. (라고 주장하지만 실제는 SQLite가 불리한 상황에서 5~10%정도 느린것같다. 빠른경우는 빠르다...)
* 하나의 구조체와 3개의 함수만 사용하는 정도로 sqlite를 사용하는 C/C++ 코드를 만들어 낼 수 있다. (코딩해보면 절대적으로 쉽다. BDB에 비해 생산성과 버그방지 소스코드 유지보수에 절대적으로 유리하다)
* TCL, Perl, PHP, .Net, Java, Python, SmallTalk, Ruby등의 다양한 언어지원 (C밖에 안써봤다ㅜ.ㅠ)
* 다른 라이브러리등의 도움없이 작동된다. libsqlite.so와 sqlite 2개의 파일이면 작동 환경을 만들 수 있다.
* [http://www.sqlite.org/copyright.html Public Domain 라이센스]를 가진다. (수정,배포 등등이 완전 자유롭다)
* 다른 라이브러리를 전혀 필요로 하지 않는다. (포팅이나 이전이 쉽다)

== Command Line Program 사용 ==

test.db라는 DB 생성
$ ./sqlite3 test.db
SQLite version 3.3.5
Enter ".help" for instructions
sqlite>


tb11이라는 테이블 생성, 테이블에 insert, select
sqlite> create table tbl1(one varchar(10), two smallint);
sqlite> insert into tbl1 values('hello!',10);
sqlite> insert into tbl1 values('goodbye', 20);
sqlite> select * from tbl1;
hello!|10
goodbye|20
sqlite>



db의 테이블 리스트 보기
sqlite> .tables
tbl1
sqlite>


cmdline 종료
sqlite> .q
$


db sql dump
$ echo '.dump' | sqlite test.db
BEGIN TRANSACTION;
CREATE TABLE tbl1(one varchar(10), two smallint);
INSERT INTO "tbl1" VALUES('hello!', 10);
INSERT INTO "tbl1" VALUES('goodbye', 20);
COMMIT;
$ echo '.dump' | sqlite test.db | gzip -c >testdb.dump.gz
$



== 기본적인 C API ==
=== sqlite3_open ===
int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);

DB File을 오픈

=== sqlite3_exec ===
int sqlite3_exec(
  sqlite3*,                     /* An open database */
  const char *sql,              /* SQL to be executed */
  sqlite_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg                 /* Error msg written here */
);

SQL문을 실행

=== sqlite3_close ===
int sqlite3_close(sqlite3*);

열려진 DB 파일을 close

=== sqlite3_mprintf ===
char *sqlite3_mprintf(const char*,...);
char *sqlite3_vmprintf(const char*, va_list);

DB의 insert문 등에서 사용할 수 없는 ' 같은 케릭터가 포함될때 SQL용으로 사용할 수 있는 케릭터로 변환시켜주는 sprintf 함수 내부적으로 malloc을 사용하기 때문에 sqlite3_free()로 free해줘야 한다.

=== sqlite3_free ===
void sqlite3_free(void*);

메모리 Free
sqlite3_mprintf(), sqlite3_vmprintf() 의 리턴값 sqlite3_exec() 의 에러값을 Free할때는 sqlite3_free()를 사용한다.

=== sqlite3_get_table ===
int sqlite3_get_table(
  sqlite3*,              /* An open database */
  const char *sql,       /* SQL to be executed */
  char ***resultp,       /* Result written to a char *[]  that this points to */
  int *nrow,             /* Number of result rows written here */
  int *ncolumn,          /* Number of result columns written here */
  char **errmsg          /* Error msg written here */
);

SQL의 실행 결과를 받아오는 함수 resultp에 내부적으로 malloc하여 가져오기 때문에 사용후 sqlite3_free_table()을 사용해야 한다.

=== sqlite3_free_table ===
void sqlite3_free_table(char **result);
sqlite3_get_table()의 결과값을 free시켜주는 함수.


== C API 사용 예 ==
=== DB Open ===
db open, timeout 500ms으로 설정, 속도를 빠르게 해주기 위한 옵션 설정.
       /* OPEN DATABASE */
       ret = sqlite3_open("cache_data/cache_db.sqlite3", &pDb);
       if (ret != SQLITE_OK)
       {
               PRINT_LOG(stdout, "OPEN ERR:%s\n", sqlite3_errmsg(pDb));
               return -1;
       }
       sqlite3_busy_timeout(pDb, 500);
       ret = sqlite3_exec(pDb,
                       "PRAGMA synchronous=OFF;
                        PRAGMA count_changes=OFF;
                        PRAGMA temp_store=memory;",
                       NULL, NULL, &errmsg);



=== 테이블 생성 ===
table과 index를 생성
int create_sqlite_table(void)
{
       int ret;
       sqlite3 *pDb;
       char *errmsg;

       ret = sqlite3_open("cache_data/cache_db.sqlite3", &pDb);
       if (ret != SQLITE_OK)
       {
               PRINT_LOG(stdout, "OPEN ERR:%s\n", sqlite3_errmsg(pDb));
               return -1;
       }

       ret = sqlite3_exec(pDb,
                       "CREATE TABLE local_search_cache ( key TEXT PRIMARY KEY,
data TEXT, date TEXT)",
                       NULL, NULL, &errmsg);
       if (ret != SQLITE_OK)
       {
               printf("Write Error: %s\n", errmsg);
               sqlite3_free(errmsg);
               return -1;
       }

       ret = sqlite3_exec(pDb,
                       "CREATE INDEX date_idx ON local_search_cache ( date DESC
)",
                       NULL, NULL, &errmsg);
       if (ret != SQLITE_OK)
       {
               printf("Write Error: %s\n", errmsg);
               sqlite3_free(errmsg);
               return -1;
       }

       sqlite3_close(pDb);
       return 0;
}



=== 데이터 읽기 ===
데이터를 읽고 필드 1개를 업데이트
int read_cache(void *pDb, char *strkey, int key_len, char *strdata, int
*data_len)
{
       int ret;
       char *buf;
       char **resultp;
       int nrow,ncol;
       char *errmsg;
       /* DATA가 있는지 확인 */
       buf = sqlite3_mprintf(
                "SELECT key,data,date FROM local_search_cache WHERE key='%q';", strkey);
       ret = sqlite3_get_table(pDb, buf, &resultp, &nrow, &ncol, &errmsg);
       sqlite3_free(buf);
       if (ret != SQLITE_OK)
       {
               PRINT_LOG(stderr, "Read SELECT Error (%s)", errmsg);
               sqlite3_free(errmsg);
               strdata[0] = '\0';
               *data_len = 0;
               return -1;
       }
       /* DATA가 없으면 */
       if (nrow ==0)
       {
               //PRINT_LOG(stderr, "Read NOTFOUND strkey(%s)\n", strkey);
               sqlite3_free_table(resultp);
               strdata[0] = '\0';
               *data_len = 0;
               return -1;
       }
       /* DATA가 있으면 리턴 */
       ret = strlen(resultp[4]);
       if (strdata)
               snprintf(strdata, ret+1, "%s", resultp[4]);
       if (data_len)
               *data_len = ret;
       sqlite3_free_table(resultp);
       /* DATA가 UPDATE access history */
       buf = sqlite3_mprintf(
             "BEGIN;UPDATE local_search_cache SET date=%d WHERE key='%q';COMMIT;"
             , (int)time(NULL), strkey);
       ret = sqlite3_exec(pDb, buf, NULL, NULL, &errmsg);
       sqlite3_free(buf);
       if (ret != SQLITE_OK)
       {
               //PRINT_LOG(stderr, "Read UPDATE ACCESS HISTORY Error (%s)", errmsg);
       }
       return 0;
}



=== 데이터 쓰기 ===
데이터를 쓰고 일정 사이즈 이상이면 1개를 삭제

int write_cache(void *pDb, char *strkey, int key_len, char *strdata, int *data_l
en)
{
       int ret;
       char *buf;
       char *errmsg;
       /* DATA가 없으면 새로 추가  있으면 UPDATE */
       buf = sqlite3_mprintf(
             "BEGIN;REPLACE INTO local_search_cache (key, data, date)
               values ('%s', '%s', %d);", strkey, strdata, (int)time(NULL));

       ret = sqlite3_exec(pDb, buf, NULL, NULL, &errmsg);
       sqlite3_free(buf);
       if (ret != SQLITE_OK)
       {
               PRINT_LOG(stderr, "Write REPLACE Error: %s\n", errmsg);
               sqlite3_free(errmsg);
               return -1;
       }
       buf = sqlite3_mprintf(
             "DELETE FROM local_search_cache WHERE
               (SELECT COUNT(key)FROM local_search_cache)>%ld
                AND key=(SELECT key FROM local_search_cache WHERE
                         date=(SELECT MIN(date) FROM local_search_cache) LIMIT 1);
              COMMIT;"
             , cache_size);
       ret = sqlite3_exec(pDb, buf, NULL, NULL, &errmsg);
       sqlite3_free(buf);
       if (ret != SQLITE_OK)
       {
               PRINT_LOG(stderr, "Write DELETE Error: %s\n", errmsg);
               sqlite3_free(errmsg);
               return -1;
       }

       return 0;
}

 

출처 : http://luzluna.tistory.com/1