[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
46 [데이터분석 & 데이터 사이언스] 수많은 데이터 사이언티스트들이 직장을 떠나는 이유는 무엇인가? file 졸리운_곰 2025.03.09 901
45 [데이터분석][파이썬][python] 한글 글꼴 사용 (matplotlib) 졸리운_곰 2024.04.18 1360
44 [데이터분석 & 데이터 사이언스] 데이터에 관한 꼭 알아야 할 오해와 진실 12가지 졸리운_곰 2024.01.17 1315
43 [데이터분석][파이썬][python] Awesome Dash Awesome file 졸리운_곰 2021.07.10 2336
42 [데이터분석][파이썬][python] ???? Introducing Dash ???? file 졸리운_곰 2021.07.10 1605
41 [dataset] (한글) 욕설 감지 데이터셋 file 졸리운_곰 2021.05.12 1559
40 [데이터분석][python] Dash를 사용하는 초보자 및 기타 모든 사용자를위한 Python의 대시 보드 file 졸리운_곰 2021.04.14 1762
39 [데이터분석][python] Dash를 사용하는 초보자 및 기타 모든 사용자를위한 Python의 대시 보드 file 졸리운_곰 2021.04.14 1602
38 [데이터분석][데이터 사이언스][python][Dash] Python, Dash 및 Plotly를 사용하여 COVID-19 사례 데이터 시각화 file 졸리운_곰 2021.03.28 1500
37 [데이터분석][머신러닝] When not to use machine learning or AI Adventures in wishful thinking, nonstationarity, and pattern-finding / 기계 학습 또는 AI를 사용하지 않아야하는 경우 희망찬 사고, 비정상 성, 패턴 찾기의 모험 file 졸리운_곰 2021.03.28 21621
36 [MSA][머신러닝] 쿠버네티스 기반의 End2End 머신러닝 플랫폼 Kubeflow #1 - 소개 file 졸리운_곰 2021.03.21 1134
35 [데이터사이언스] 데이터 과학자를위한 3 가지 훌륭한 디자인 패턴, 3 Great Design Patterns for Data Scientists file 졸리운_곰 2021.03.04 779
34 [데이터분석] 시계열 데이터에 AI를 사용하는 이유는 무엇입니까? file 졸리운_곰 2021.02.28 1191
33 [데이터분석] AI 예측 및 이상 탐지를위한 시계열 데이터 전처리 file 졸리운_곰 2021.02.28 1030
32 [데이터분석] bitcoin analysis 비트 코인 시계열 데이터에 대한 AI 이상 탐지 file 졸리운_곰 2021.02.27 1587
31 [데이터분석 & 데이터 사이언스] How To Create a Data Science Portfolio Website file 졸리운_곰 2021.02.14 1823
30 [데이터수집4] 오픈 API 데이터 수집 (소셜미디어 데이터 수집) file 졸리운_곰 2020.06.12 1950
29 [데이터수집3] 관계형 데이터베이스 데이터 수집 file 졸리운_곰 2020.06.12 1315
28 [데이터수집2] 분산시스템 로그 수집 (빅데이터 수집) file 졸리운_곰 2020.06.12 1492
27 [데이터수집1] 웹 크롤링, 웹 스크래핑 file 졸리운_곰 2020.06.12 1802
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED