[C/C++] SQLite 의 모든 것 (3부) - C++ 에서 사용하기 Database/SQLite  


기본코드


개발자에게 그 어떤 설명들보다, 코드가 더 이해하기 쉽다고 생각합니다. :)
기본적인 Insert, Delete, Create 들을 어떻게 사용하는지 아래 코드를 먼저 참고하시기 바랍니다.

추가적인 설명들은 아래에서 따로 하겠습니다.

 
    [CrystalDB.h]

 


#pragma once

#include <iostream>
#include <list>
#include "sqlite3.h"

static const std::wstring QUERY_TABLE_CREATE  
	= L"CREATE TABLE CRYSTAL_CUBE (FilePath TEXT PRIMARY KEY NOT NULL, CheckSum TEXT, Image BLOB);" ;

static const std::wstring QUERY_TABLE_EXIST
	= L"SELECT name FROM sqlite_master WHERE type='table' AND name='CRYSTAL_CUBE';";

static const std::wstring QUERY_TABLE_DROP
	= L"DROP TABLE IF EXISTS CRYSTAL_CUBE;";

static const std::wstring QUERY_TABLE_EXIST_RECORD
	= L"SELECT FilePath FROM CRYSTAL_CUBE WHERE FilePath=? AND CheckSum=? AND Version=?;";

static const std::wstring QUERY_TABLE_DELETE_RECORD
	= L"DELETE FROM CRYSTAL_CUBE WHERE FilePath=?;";

static const std::wstring QUERY_TABLE_UPSERT_RECORD
	= L"INSERT OR REPLACE INTO CRYSTAL_CUBE VALUES(?, ?, ?);";

static const std::wstring QUERY_TABLE_SELECT_ALL
	= L"SELECT FilePath FROM CRYSTAL_CUBE;";

static const std::wstring QUERY_DB_CLEAN_UP
	= L"VACUUM;";

static const std::wstring QUERY_DB_BEGIN
	= L"BEGIN;";

static const std::wstring QUERY_DB_COMMIT
	= L"COMMIT;";

static const std::wstring QUERY_DB_ROLLBACK
    = L"ROLLBACK;";


class __declspec(dllexport) CrystalDB
{
private:
	   sqlite3 *db;

public: 
	bool Open(std::wstring dbFileName);
	bool Close();   
	bool Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size)bool Delete(std::wstring key)std::list<std::wstring> GetAllRecords();

privatebool DropTable();   
	bool CreateTable(); 
	bool IsTableExist();

private:    
	bool Begin();   
	bool Commit()bool Rollback();
};


 

 

 
    [CrystalDB.cpp]

 


#include <stdio.h>
#include "sqlite3.h"
#include "CrystalDB.h"


//### public ###

bool CrystalDB::Open(std::wstring dbFileName){
	int rc = sqlite3_open16(dbFileName.c_str(), &db);   
	if(rc != SQLITE_OK) { 
		sqlite3_close(db);
		return false;   
	}   
	
	// table check  
	if(this->IsTableExist() == false) {
		this->CreateTable(); 
	}   
	return true;
}



bool CrystalDB::Close()
{   
	return (sqlite3_close(db) == SQLITE_OK);
}



bool CrystalDB::Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size) {
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_UPSERT_RECORD.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);   
	sqlite3_bind_text16(stmt, 22, checksum.c_str(), -1,SQLITE_STATIC);  

	if(binaryData == NULL) {        
		sqlite3_bind_blob(stmt, 23, NULL, -1,SQLITE_STATIC);    
	} else {        
		sqlite3_bind_blob(stmt, 23, binaryData, size, SQLITE_TRANSIENT);    
	}   

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) 
	{ 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db));
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



bool CrystalDB::Delete(std::wstring filePath) 
{
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DELETE_RECORD.c_str();
	bool result = true; 
	
	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);       
	
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



std::list<std::wstring> CrystalDB::GetAllRecords()
{    
	std::list<std::wstring> result;   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_SELECT_ALL.c_str(); 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	while(sqlite3_step(stmt) == SQLITE_ROW) 
	{
		int type = sqlite3_column_type(stmt, 0);        
		if(type != SQLITE_TEXT) { continue; }       
		std::wstring fileName((wchar_t *)sqlite3_column_text16(stmt, 0));       
		result.push_back(fileName); 
	}   

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}





//### private ###
bool CrystalDB::DropTable()
{    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DROP.c_str();   
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);    
	  
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();      

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::CreateTable(){   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_CREATE.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::IsTableExist(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_EXIST.c_str();  
	bool result = false;    

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) == SQLITE_ROW) {
		result = true; 
	} 
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Begin(){ 
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_BEGIN.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Commit(){    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_COMMIT.c_str();    
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Rollback(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_ROLLBACK.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}




 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 



기본적인 동작은 보시는 것과 같습니다.

1. Database 를 Open 한다.
2. query 를 보낸다.
3. Database 를 Close 한다. 

VACUUM 에 대해서 설명드리자면,
sqlite 는 기본적으로 data 를 삭제하더라도, 파일의 크기가 줄어들지 않습니다.
예약 공간으로 놔두고, 다음 사용하게 되어 있지요.

만약 data 삭제 후, 파일 크기를 줄이고 싶다면 VACUUM 명령을 내려주면 됩니다.
단, sqlite 문서를 보면, 이 작업에 오버헤드가 많이 걸린다고 되어 있습니다.
이전 포스팅을 보시면 나와 있는데, 지금 기억으로는 1 메가당 0.5 초인가? 걸린다고 했던것 같네요.

그러므로 query 를 보낼때마다 VACUUM 하는 일은 없어야 합니다.

또 한가지 드릴 말씀은. BLOB 인데,
이 녀석은 binary 를 데이터로 받습니다.(물론 다른 타입도 됩니다. - 자세한건 이전 포스팅 FAQ 참고)
저는 처음에 엄청 고생했습니다.
좋지 않은 방법이지만, 일이 좀 있어서 Database 에 Image 를 통째로 넣어야 했습니다.

그런데 넣고나서 SQLite  Viewer 로 열어보았더니, Image Header 부분(약 10 byte?)만 들어간 것입니다.
이녀석이 내부적으로

[C/C++] SQLite 의 모든 것 (3부) - C++ 에서 사용하기 Database/SQLite  


기본코드


개발자에게 그 어떤 설명들보다, 코드가 더 이해하기 쉽다고 생각합니다. :)
기본적인 Insert, Delete, Create 들을 어떻게 사용하는지 아래 코드를 먼저 참고하시기 바랍니다.

추가적인 설명들은 아래에서 따로 하겠습니다.

 
    [CrystalDB.h]

 


#pragma once

#include <iostream>
#include <list>
#include "sqlite3.h"

static const std::wstring QUERY_TABLE_CREATE  
	= L"CREATE TABLE CRYSTAL_CUBE (FilePath TEXT PRIMARY KEY NOT NULL, CheckSum TEXT, Image BLOB);" ;

static const std::wstring QUERY_TABLE_EXIST
	= L"SELECT name FROM sqlite_master WHERE type='table' AND name='CRYSTAL_CUBE';";

static const std::wstring QUERY_TABLE_DROP
	= L"DROP TABLE IF EXISTS CRYSTAL_CUBE;";

static const std::wstring QUERY_TABLE_EXIST_RECORD
	= L"SELECT FilePath FROM CRYSTAL_CUBE WHERE FilePath=? AND CheckSum=? AND Version=?;";

static const std::wstring QUERY_TABLE_DELETE_RECORD
	= L"DELETE FROM CRYSTAL_CUBE WHERE FilePath=?;";

static const std::wstring QUERY_TABLE_UPSERT_RECORD
	= L"INSERT OR REPLACE INTO CRYSTAL_CUBE VALUES(?, ?, ?);";

static const std::wstring QUERY_TABLE_SELECT_ALL
	= L"SELECT FilePath FROM CRYSTAL_CUBE;";

static const std::wstring QUERY_DB_CLEAN_UP
	= L"VACUUM;";

static const std::wstring QUERY_DB_BEGIN
	= L"BEGIN;";

static const std::wstring QUERY_DB_COMMIT
	= L"COMMIT;";

static const std::wstring QUERY_DB_ROLLBACK
    = L"ROLLBACK;";


class __declspec(dllexport) CrystalDB
{
private:
	   sqlite3 *db;

public: 
	bool Open(std::wstring dbFileName);
	bool Close();   
	bool Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size)bool Delete(std::wstring key)std::list<std::wstring> GetAllRecords();

privatebool DropTable();   
	bool CreateTable(); 
	bool IsTableExist();

private:    
	bool Begin();   
	bool Commit()bool Rollback();
};


 

 

 
    [CrystalDB.cpp]

 


#include <stdio.h>
#include "sqlite3.h"
#include "CrystalDB.h"


//### public ###

bool CrystalDB::Open(std::wstring dbFileName){
	int rc = sqlite3_open16(dbFileName.c_str(), &db);   
	if(rc != SQLITE_OK) { 
		sqlite3_close(db);
		return false;   
	}   
	
	// table check  
	if(this->IsTableExist() == false) {
		this->CreateTable(); 
	}   
	return true;
}



bool CrystalDB::Close()
{   
	return (sqlite3_close(db) == SQLITE_OK);
}



bool CrystalDB::Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size) {
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_UPSERT_RECORD.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);   
	sqlite3_bind_text16(stmt, 22, checksum.c_str(), -1,SQLITE_STATIC);  

	if(binaryData == NULL) {        
		sqlite3_bind_blob(stmt, 23, NULL, -1,SQLITE_STATIC);    
	} else {        
		sqlite3_bind_blob(stmt, 23, binaryData, size, SQLITE_TRANSIENT);    
	}   

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) 
	{ 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db));
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



bool CrystalDB::Delete(std::wstring filePath) 
{
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DELETE_RECORD.c_str();
	bool result = true; 
	
	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);       
	
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



std::list<std::wstring> CrystalDB::GetAllRecords()
{    
	std::list<std::wstring> result;   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_SELECT_ALL.c_str(); 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	while(sqlite3_step(stmt) == SQLITE_ROW) 
	{
		int type = sqlite3_column_type(stmt, 0);        
		if(type != SQLITE_TEXT) { continue; }       
		std::wstring fileName((wchar_t *)sqlite3_column_text16(stmt, 0));       
		result.push_back(fileName); 
	}   

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}





//### private ###
bool CrystalDB::DropTable()
{    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DROP.c_str();   
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);    
	  
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();      

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::CreateTable(){   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_CREATE.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::IsTableExist(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_EXIST.c_str();  
	bool result = false;    

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) == SQLITE_ROW) {
		result = true; 
	} 
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Begin(){ 
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_BEGIN.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Commit(){    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_COMMIT.c_str();    
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Rollback(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_ROLLBACK.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}




 

 



기본적인 동작은 보시는 것과 같습니다.

1. Database 를 Open 한다.
2. query 를 보낸다.
3. Database 를 Close 한다. 

VACUUM 에 대해서 설명드리자면,
sqlite 는 기본적으로 data 를 삭제하더라도, 파일의 크기가 줄어들지 않습니다.
예약 공간으로 놔두고, 다음 사용하게 되어 있지요.

만약 data 삭제 후, 파일 크기를 줄이고 싶다면 VACUUM 명령을 내려주면 됩니다.
단, sqlite 문서를 보면, 이 작업에 오버헤드가 많이 걸린다고 되어 있습니다.
이전 포스팅을 보시면 나와 있는데, 지금 기억으로는 1 메가당 0.5 초인가? 걸린다고 했던것 같네요.

그러므로 query 를 보낼때마다 VACUUM 하는 일은 없어야 합니다.

또 한가지 드릴 말씀은. BLOB 인데,
이 녀석은 binary 를 데이터로 받습니다.(물론 다른 타입도 됩니다. - 자세한건 이전 포스팅 FAQ 참고)
저는 처음에 엄청 고생했습니다.
좋지 않은 방법이지만, 일이 좀 있어서 Database 에 Image 를 통째로 넣어야 했습니다.

그런데 넣고나서 SQLite  Viewer 로 열어보았더니, Image Header 부분(약 10 byte?)만 들어간 것입니다.
이녀석이 내부적으로 \00, \0000 등을 만나면 입력을 더이상 안하는 것이죠.

그런데...알고보니...............
안들어간게 아니라, Viewer 가 표시를 그렇게 하는 거였습니다. orz
실제로 database 에서 꺼내서 Image 로 복원하면 잘 나오더군요.

개인적으로 이런 일이 있은 후에는, FireFox 에서 제공하는 sqlite Manager 플러그인을 사용하고 있습니다. :)

자세히 사용법에 대해서 설명을 드리고 싶었는데,
크게 어려운게 없어서 간단히 여기까지만 하고 마치도록 하겠습니다.

참, 마지막으로 이전 포스팅의 FAQ 를 꼭 읽어 보시기 바랍니다.
도움이 될 만한 많은 내용이 나와 있습니다. ^-^
길이도 않아서 10분이면 다 보실것 같네요.



출처: https://crystalcube.co.kr/92?category=412659 [유리상자 속 이야기]

 

 

,

[C/C++] SQLite 의 모든 것 (3부) - C++ 에서 사용하기 Database/SQLite  


기본코드


개발자에게 그 어떤 설명들보다, 코드가 더 이해하기 쉽다고 생각합니다. :)
기본적인 Insert, Delete, Create 들을 어떻게 사용하는지 아래 코드를 먼저 참고하시기 바랍니다.

추가적인 설명들은 아래에서 따로 하겠습니다.

 
    [CrystalDB.h]

 


#pragma once

#include <iostream>
#include <list>
#include "sqlite3.h"

static const std::wstring QUERY_TABLE_CREATE  
	= L"CREATE TABLE CRYSTAL_CUBE (FilePath TEXT PRIMARY KEY NOT NULL, CheckSum TEXT, Image BLOB);" ;

static const std::wstring QUERY_TABLE_EXIST
	= L"SELECT name FROM sqlite_master WHERE type='table' AND name='CRYSTAL_CUBE';";

static const std::wstring QUERY_TABLE_DROP
	= L"DROP TABLE IF EXISTS CRYSTAL_CUBE;";

static const std::wstring QUERY_TABLE_EXIST_RECORD
	= L"SELECT FilePath FROM CRYSTAL_CUBE WHERE FilePath=? AND CheckSum=? AND Version=?;";

static const std::wstring QUERY_TABLE_DELETE_RECORD
	= L"DELETE FROM CRYSTAL_CUBE WHERE FilePath=?;";

static const std::wstring QUERY_TABLE_UPSERT_RECORD
	= L"INSERT OR REPLACE INTO CRYSTAL_CUBE VALUES(?, ?, ?);";

static const std::wstring QUERY_TABLE_SELECT_ALL
	= L"SELECT FilePath FROM CRYSTAL_CUBE;";

static const std::wstring QUERY_DB_CLEAN_UP
	= L"VACUUM;";

static const std::wstring QUERY_DB_BEGIN
	= L"BEGIN;";

static const std::wstring QUERY_DB_COMMIT
	= L"COMMIT;";

static const std::wstring QUERY_DB_ROLLBACK
    = L"ROLLBACK;";


class __declspec(dllexport) CrystalDB
{
private:
	   sqlite3 *db;

public: 
	bool Open(std::wstring dbFileName);
	bool Close();   
	bool Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size)bool Delete(std::wstring key)std::list<std::wstring> GetAllRecords();

privatebool DropTable();   
	bool CreateTable(); 
	bool IsTableExist();

private:    
	bool Begin();   
	bool Commit()bool Rollback();
};


 

 

 
    [CrystalDB.cpp]

 


#include <stdio.h>
#include "sqlite3.h"
#include "CrystalDB.h"


//### public ###

bool CrystalDB::Open(std::wstring dbFileName){
	int rc = sqlite3_open16(dbFileName.c_str(), &db);   
	if(rc != SQLITE_OK) { 
		sqlite3_close(db);
		return false;   
	}   
	
	// table check  
	if(this->IsTableExist() == false) {
		this->CreateTable(); 
	}   
	return true;
}



bool CrystalDB::Close()
{   
	return (sqlite3_close(db) == SQLITE_OK);
}



bool CrystalDB::Upsert(std::wstring filePath, std::wstring checksum, void * binaryData, int size) {
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_UPSERT_RECORD.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);   
	sqlite3_bind_text16(stmt, 22, checksum.c_str(), -1,SQLITE_STATIC);  

	if(binaryData == NULL) {        
		sqlite3_bind_blob(stmt, 23, NULL, -1,SQLITE_STATIC);    
	} else {        
		sqlite3_bind_blob(stmt, 23, binaryData, size, SQLITE_TRANSIENT);    
	}   

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) 
	{ 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db));
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



bool CrystalDB::Delete(std::wstring filePath) 
{
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DELETE_RECORD.c_str();
	bool result = true; 
	
	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	sqlite3_bind_text16(stmt, 1, filePath.c_str(), -1,SQLITE_STATIC);       
	
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 
	return result;
}



std::list<std::wstring> CrystalDB::GetAllRecords()
{    
	std::list<std::wstring> result;   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_SELECT_ALL.c_str(); 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	while(sqlite3_step(stmt) == SQLITE_ROW) 
	{
		int type = sqlite3_column_type(stmt, 0);        
		if(type != SQLITE_TEXT) { continue; }       
		std::wstring fileName((wchar_t *)sqlite3_column_text16(stmt, 0));       
		result.push_back(fileName); 
	}   

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}





//### private ###
bool CrystalDB::DropTable()
{    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_DROP.c_str();   
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);    
	  
	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();      

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::CreateTable(){   
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_CREATE.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  

	// begin    
	this->Begin();   
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	// commit   
	this->Commit();  

	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::IsTableExist(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_TABLE_EXIST.c_str();  
	bool result = false;    

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) == SQLITE_ROW) {
		result = true; 
	} 
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Begin(){ 
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_BEGIN.c_str(); 
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Commit(){    
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_COMMIT.c_str();    
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}



bool CrystalDB::Rollback(){  
	sqlite3_stmt * stmt;    
	const wchar_t * query = QUERY_DB_ROLLBACK.c_str();  
	bool result = true; 

	sqlite3_prepare16_v2(this->db, query, -1, &stmt, NULL);  
	if(sqlite3_step(stmt) != SQLITE_DONE) { 
		fwprintf(stderr, L"line %d: %s\n", __LINE__, sqlite3_errmsg16(this->db)); 
		result = false; 
	}  
	sqlite3_reset(stmt);    
	sqlite3_finalize(stmt); 

	return result;
}




 

 



기본적인 동작은 보시는 것과 같습니다.

1. Database 를 Open 한다.
2. query 를 보낸다.
3. Database 를 Close 한다. 

VACUUM 에 대해서 설명드리자면,
sqlite 는 기본적으로 data 를 삭제하더라도, 파일의 크기가 줄어들지 않습니다.
예약 공간으로 놔두고, 다음 사용하게 되어 있지요.

만약 data 삭제 후, 파일 크기를 줄이고 싶다면 VACUUM 명령을 내려주면 됩니다.
단, sqlite 문서를 보면, 이 작업에 오버헤드가 많이 걸린다고 되어 있습니다.
이전 포스팅을 보시면 나와 있는데, 지금 기억으로는 1 메가당 0.5 초인가? 걸린다고 했던것 같네요.

그러므로 query 를 보낼때마다 VACUUM 하는 일은 없어야 합니다.

또 한가지 드릴 말씀은. BLOB 인데,
이 녀석은 binary 를 데이터로 받습니다.(물론 다른 타입도 됩니다. - 자세한건 이전 포스팅 FAQ 참고)
저는 처음에 엄청 고생했습니다.
좋지 않은 방법이지만, 일이 좀 있어서 Database 에 Image 를 통째로 넣어야 했습니다.

그런데 넣고나서 SQLite  Viewer 로 열어보았더니, Image Header 부분(약 10 byte?)만 들어간 것입니다.
이녀석이 내부적으로 \00, \0000 등을 만나면 입력을 더이상 안하는 것이죠.

그런데...알고보니...............
안들어간게 아니라, Viewer 가 표시를 그렇게 하는 거였습니다. orz
실제로 database 에서 꺼내서 Image 로 복원하면 잘 나오더군요.

개인적으로 이런 일이 있은 후에는, FireFox 에서 제공하는 sqlite Manager 플러그인을 사용하고 있습니다. :)

자세히 사용법에 대해서 설명을 드리고 싶었는데,
크게 어려운게 없어서 간단히 여기까지만 하고 마치도록 하겠습니다.

참, 마지막으로 이전 포스팅의 FAQ 를 꼭 읽어 보시기 바랍니다.
도움이 될 만한 많은 내용이 나와 있습니다. ^-^
길이도 않아서 10분이면 다 보실것 같네요.



출처: https://crystalcube.co.kr/92?category=412659 [유리상자 속 이야기]

 

 

00 등을 만나면 입력을 더이상 안하는 것이죠.

그런데...알고보니...............
안들어간게 아니라, Viewer 가 표시를 그렇게 하는 거였습니다. orz
실제로 database 에서 꺼내서 Image 로 복원하면 잘 나오더군요.

개인적으로 이런 일이 있은 후에는, FireFox 에서 제공하는 sqlite Manager 플러그인을 사용하고 있습니다. :)

자세히 사용법에 대해서 설명을 드리고 싶었는데,
크게 어려운게 없어서 간단히 여기까지만 하고 마치도록 하겠습니다.

참, 마지막으로 이전 포스팅의 FAQ 를 꼭 읽어 보시기 바랍니다.
도움이 될 만한 많은 내용이 나와 있습니다. ^-^
길이도 않아서 10분이면 다 보실것 같네요.



출처: https://crystalcube.co.kr/92?category=412659 [유리상자 속 이야기]

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
공지 오라클 기본 샘플 데이터베이스 졸리운_곰 2014.01.02 86034
공지 [SQL컨셉] 서적 "SQL컨셉"의 샘플 데이타 베이스 SAMPLE DATABASE of ORACLE 가을의 곰을... 2013.02.10 78561
공지 [G_SQL] Sample Database 가을의 곰을... 2012.05.20 95291
27 [java dbms][database] [컴] Apache Derby 사용하기 - 4 - in-memory DB 졸리운_곰 2021.04.15 1559
26 [java dbms][database] [컴] Apache Derby 사용하기 - 3 - Apache Derby Network Server 졸리운_곰 2021.04.15 1634
25 [java dbms][database] [컴] Apache Derby 사용하기 - 2 - sql script tool ij 사용하기 졸리운_곰 2021.04.15 1823
24 [java dbms][database] [컴] Apache Derby 사용하기 - 1 - Derby 설치 file 졸리운_곰 2021.04.15 1152
23 실습 2 - GROUP 졸리운_곰 2020.09.30 1550
22 [SQL 가이드] 데이터베이스 모델의 이해 (Understanding Database model) file 졸리운_곰 2020.06.13 2480
21 [SQL 가이드] 식별자(Identification)의 개념 file 졸리운_곰 2020.06.13 2058
20 [SQL 가이드] 관계(relationship)의 개념 file 졸리운_곰 2020.06.13 1555
19 [SQL 가이드] 속성(attribute)의 개념 file 졸리운_곰 2020.06.13 1703
18 [SQL 가이드] 엔티티의 개념 file 졸리운_곰 2020.06.13 2198
17 [SQL] join의 on절과 where절 차이 졸리운_곰 2020.05.16 1303
16 JOIN*(3개 테이블) and GROUP BY*(보이지않더라도 key칼럼으로) and ORDER BY 졸리운_곰 2020.05.16 1224
15 다중 테이블에서 데이터 검색 - JOIN file 졸리운_곰 2020.05.16 1594
14 IFNULL(MYSQL), ISNULL(MSSQL), NVL(ORACLE) 졸리운_곰 2018.07.24 1778
13 4 Ways to Join Only The First Row in SQL file 졸리운_곰 2018.07.03 1637
12 DBMS별 기존테이블 SELECT해서 새 테이블에 INSERT하여 데이터 ... file 졸리운_곰 2018.01.22 1592
11 SOL 개발자의 현주소 : 개발자가 SQL 작성시 고쳐야 하는 태도 file 졸리운_곰 2018.01.01 2158
10 오라클 운반 최소 단위 BLOCK file 졸리운_곰 2017.07.15 2035
9 재미있는 DB 이야기 ‘놀라운 마방진의 세계’ file 졸리운_곰 2017.07.15 2393
8 재미있는 DB 이야기 ‘사라진 날짜를 찾아라’ file 졸리운_곰 2017.07.15 2222
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED