데이터 베이스 파일 형식도 바꼈습니다. 그래서 sqlite2에서 만든 데이터베이스 파일은 sqlite3에서 읽을 수 없습니다. 때문에 다음과 같은 방법으로 데이터 베이스를 옮겨야 합니다.
# sqlite OLD.db .dump | sqlite3 NEW.db
헤더파일
헤더파일도 sqlite.h에서 sqlite3.h로 바꼈습니다.
링크
-lsqlite 대신 -lsqlite3를 사용해야 합니다.
64-bit ROWID
sqlite는 엔진에서 insert 레코드에 물리적인 일련 번호를 부여합니다. 일련번호를 부여하기 위한 방법을 고민해 보신적이 있을 겁니다. rowid 덕분에 sqlite에서는 유일한 일련번호를 얻기 위한 고민을 할 필요가 없습니다. 참고로 만약 테이블의 컬럼을 INTEGER PRIMARY KEY형식으로 하면 rowid를 가리킵니다.
이 크기가 32bit에서 64bit로 바꼈습니다.
improved concurrency
sqlite2 버전은 동시에 여러 유저가 읽을 수 있도록 허용했으나 쓰는 것은 허용하지 않았습니다. sqlite3는 읽기와 쓰기 모두에 동시 접근을 허용합니다.
UTF-8과 UTF-16 지원
UTF-8과 UTF-16 모두를 지원한다는 군요. 좋은 세상입니다. ?
프로그래밍 형식
callback 호출 방식
callback 함수를 호출하면 좀더 쉽게 레코드를 다룰 수 있습니다. row와 column단위로 데이터를 처리한다음에 이에 대한 포인터를 callback의 매개 변수로 넘겨주기 때문입니다.
콜백함수를 호출하면 간단하게 데이터를 다룰 수 있습니다. 하지만 static 함수를 호출하기 때문에, c++등에서 추상화 단계를 밟으려면 애로사항이 꽃핍니다.
저는 sqlite 클래스를 만들고, 데이터 베이스를 필요로 하는 하는 클래스는 sqlite 클래스를 상속받아서 사용하길 원했습니다. 이 경우 callback 함수를 사용하는 것은 좋은 선택이 아닙니다.
그래서 낮은 수준에서 직접 다루기 원했습니다.
#include <sqlite3.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Sqlite
{
private:
sqlite3 *mdb;
string mdbname;
sqlite3_stmt *stmt;
vector<string> mRow;
bool classCheckFlag;
public:
Sqlite(string adbname)
{
int rc;
classCheckFlag = false;
mdbname = adbname;
// DB 열기
rc = sqlite3_open(mdbname.c_str(), &mdb);
if(rc == SQLITE_OK)
{
classCheckFlag = true;
}
}
~Sqlite()
{
sqlite3_close(mdb);
}
bool ClassCheck()
{
return classCheckFlag;
}
int Exec(string sql)
{
int rc;
// sql을 실행한다.
rc = sqlite3_prepare(mdb, sql.c_str(), sql.length(), &stmt, NULL);
if(rc != SQLITE_OK)
{
return 1;
}
return 0;
}
vector<string> GetRows()
{
int rc;
int n;
int i;
char buf[80];
mRow.clear();
// sqlite3_step로 row 데이터를 하나씩 가져온다.
rc = sqlite3_step(stmt);
if(rc != SQLITE_DONE)
{
switch(rc)
{
case SQLITE_BUSY:
break;
case SQLITE_ERROR:
break;
// row 데이터를 가져왔다면
// 컬럼 데이터를 읽어온다.
// 귀찮아서 컬럼 타입에 관계 없이 전부 string으로 넣어버렸다.
case SQLITE_ROW:
n = sqlite3_column_count(stmt);
for(i = 0; i < n ; i++)
{
switch(sqlite3_column_type(stmt, i))
{
case SQLITE_TEXT:
mRow.push_back((const char *)sqlite3_column_text(stmt, i));
break;
case SQLITE_INTEGER:
sprintf(buf, "%d", sqlite3_column_int(stmt, i));
mRow.push_back(buf);
break;
case SQLITE_FLOAT:
sprintf(buf, "%f", sqlite3_column_double(stmt, i));
mRow.push_back(buf);
break;
case SQLITE_NULL:
mRow.push_back("");
break;
default:
cout << "Unknown Field" << endl;
break;
}
}
break;
case SQLITE_MISUSE:
break;
default:
break;
}
}
else
{
cout << "SQL Exec Complete" << endl;
}
return mRow;
}
void ExecFree()
{
sqlite3_finalize(stmt);
}
int Exec(string sql, int (*callback)(void*,int,char**,char**))
{
int rc;
rc = sqlite3_exec(mdb, sql.c_str(), callback, 0, NULL);
if(rc != SQLITE_OK)
{
return 1;
}
return 0;
}
};
int main()
{
vector<string> Row;
Sqlite mySql("test.db");
if(!mySql.ClassCheck())
{
return 1;
}
mySql.Exec("select * from address");
int i;
for(;;)
{
Row = mySql.GetRows();
if(Row.size() > 0)
{
for(i = 0; i < Row.size(); i++)
{
cout << Row[i] << " ";
}
cout << endl;
}
else
{
break;
}
}
mySql.ExecFree();
}
SQLite 3
달라진 점
이름
DB 형식
헤더파일
링크
64-bit ROWID
improved concurrency
UTF-8과 UTF-16 지원
프로그래밍 형식
callback 호출 방식
직접 다루기
Recent Posts
Archive Posts
Tags