sqlite + kyotocabinet 사용

2023. 3. 15. 19:47프로그래밍

728x90

그럼 이 둘을 한데 합쳐서 만들게 된다면 다음 코드 정도가 된다.

void makeFileDB2SqliteDB(const pconnstrct connOpts)
{
	int rc;
	char err[5112];
	char *errmsg;
	int total_cnt =0;
	int fileCnt = 0;
	
   	sqlite3_stmt *stmt;
	sqlite3 *ptrSqliteConv;
	
	makeSqliteDBTable(connOpts);
	
	FileDBMgr->openSqliteConv(connOpts);
	FileDBMgr->openRNoSql(connOpts);
	
	ptrSqliteConv = FileDBMgr->ptrSqliteConv();
	
	loadSQLStmtParam(connOpts, MISS_FILE_INFO_TABLE_NAME, "insert"); 
	
	rc = sqlite3_prepare_v2(ptrSqliteConv, getSQLStmt(connOpts), -1, &stmt, 0);
	
	LOG_TRACE(LOG_INFO, "2. [%s]\n%s\n", __FUNCTION__, getSQLStmt(connOpts));
    LOG_TRACE(LOG_INFO, "\n2. [%s]The statement has %d wildcards\n", __FUNCTION__, sqlite3_bind_parameter_count(stmt));
    
    if (rc != SQLITE_OK) {
    	LOG_TRACE(LOG_ERROR, "Failed to execute statement: %s\n", sqlite3_errmsg(ptrSqliteConv));
    	
    	return;
	}
	
	string ckey, cvalue;
	DB::Cursor* cur;

	fileCnt = 0;
	
	sqlite3_exec(ptrSqliteConv, "BEGIN TRANSACTION", NULL, NULL, &errmsg);
	
	cur = FileDBMgr->ptrRNoSqlDB()->cursor();
	cur->jump();

	while (cur->get(&ckey, &cvalue, true)) {
		fileCnt++;
		
		insertArrangMissingFileInfo(ptrSqliteConv, stmt, ckey, cvalue);
			
		if(((fileCnt % PRINT_CNT) == 0))
		{	
			LOG_TRACE(LOG_ERROR, ".");
		}
		
		ckey.clear();
		cvalue.clear();
	}
	
	delete cur;
	
	
	sqlite3_exec(ptrSqliteConv, "END TRANSACTION", NULL, NULL, &errmsg);
	sqlite3_exec(ptrSqliteConv, "COMMIT TRANSACTION", NULL, NULL, &errmsg);
	
	LOG_TRACE(LOG_ERROR, "\r\n");
	sqlite3_finalize(stmt);	
    
	LOG_TRACE(LOG_ERROR, "total...: %d\n", fileCnt);
	
    FileDBMgr->closeSqlite(ptrSqliteConv);
   	FileDBMgr->closeRNoSql();
}
 

1. 선행 작업 진행

데이터를 집어 넣기 전에 테이블을 생성 한다.

makeSqliteDBTable(connOpts);
 

코드의 내용은 별 것 없으니, 설명한다면 sqlite 데이터베이스 열고, 테이블 스키마 대로 테이블을 생성하고, 인덱스를 생성 해 준 다음 열어논 sqlite 데이터베이스를 닫는 함수 이다.

 

 

2. 데이터 베이스 열기

sqlite과 kyotocabinet 데이터베이스를 다음과 같이 열어 준다.

FileDBMgr->openSqliteConv(connOpts);
FileDBMgr->openRNoSql(connOpts);
 

해당 sqlite 데이터베이스의 포인터를 얻는다.

ptrSqliteConv = FileDBMgr->ptrSqliteConv();
 

물론, 열면서 바로 얻을 수 있을 것인데, 그냥 내 맘대로 그렇게 했다.

 

3. 쿼리 문장 얻기

그런 다음, prepared 할 sql 문장을 xml 파일에서 준비한다.

loadSQLStmtParam(connOpts, MISS_FILE_INFO_TABLE_NAME, "insert");
 

사실 여기에는 약간의 히스토리가 있는 데, 다음 문서에 위의 내용이 있다.

[C-tinyXML] Sqlite 데이터베이스에 도로명 주소 테이블 만들어 보기 – XML 파일 바인딩

 

함수가 약간 변형 되긴 했는데...다음과 같이 했다.

내부적으로 loadQueryScheme 라는 함수를 사용하는 wrapper 함수 정도로 생각하면 된다.

void loadQueryScheme(const char *filename, char *elem, char *subelem, char **text)
{
#ifdef USING_POINTER_XML
	tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument(true, COLLAPSE_WHITESPACE);
	doc->LoadFile( filename );
	
	XMLElement* element = doc->RootElement();
	
	doc->PrintError();
	
#else
	tinyxml2::XMLDocument doc( true, COLLAPSE_WHITESPACE );
	
	doc.LoadFile( filename );
	//doc.Print();
	
	const XMLElement* element = doc.RootElement();
	
	doc.PrintError();
	
#endif
	
	const char *contents = element->FirstChildElement(elem)->FirstChildElement(subelem)->GetText();
	memcpy(*text, contents, strlen(contents) + 1);
	
#ifdef USING_POINTER_XML
	delete doc;
#endif
	return;
}
 

그리고 본 함수는 다음과 같다.

int loadSQLStmt(pconnstrct constr)
{
	char *psqlbuf;
	
	psqlbuf = constr->sqlbuf;
	
	loadQueryScheme(constr->schemefile, constr->table_name, constr->operation, &psqlbuf);
	LOG_TRACE(LOG_DEBUG, "[%s]/%s/%s/%s/%s\n\n", 
		__FUNCTION__, constr->schemefile, constr->table_name, constr->operation, constr->sqlbuf);
	//LOG_TRACE(LOG_ERROR, "%s \n", constr->sqlbuf);
		
	return 0;
}
 

4. 쿼리 문장 바인딩하기.

찾은 쿼리 문장을 다음과 같이 prepare 한다.

rc = sqlite3_prepare_v2(ptrSqliteConv, getSQLStmt(connOpts), -1, &stmt, 0);
 

5. kyotocabinet 데이터 검색하기.

여기서는 파일 내에 있는 데이터를 모두 검색 하는 것으로 진행 하는 데, 주요 원형은 다음과 같다.

string ckey, cvalue;
DB::Cursor* cur;

fileCnt = 0;

cur = FileDBMgr->ptrRNoSqlDB()->cursor();
cur->jump();

while (cur->get(&ckey, &cvalue, true)) {
	fileCnt++;
	
	insertInfo(ptrSqliteConv, stmt, ckey, cvalue);
		
	if(((fileCnt % PRINT_CNT) == 0))
	{	
		LOG_TRACE(LOG_ERROR, ".");
	}
	
	ckey.clear();
	cvalue.clear();
}

delete cur;
 

내용은 코드에서 짐작 하듯이 string 값에다 key,value을 얻어와서는 해당 정보를 넣어 주는 것이다.

 

6. 트랜잭션 처리하기- sqlite

트랜잭션은 다음과 같이 처리 한다.

sqlite3_exec(ptrSqliteConv, "BEGIN TRANSACTION", NULL, NULL, &errmsg);
....코드 ....
sqlite3_exec(ptrSqliteConv, "END TRANSACTION", NULL, NULL, &errmsg);
sqlite3_exec(ptrSqliteConv, "COMMIT TRANSACTION", NULL, NULL, &errmsg);
 

7, 데이터베이스 닫아 주기

FileDBMgr->closeSqlite(ptrSqliteConv);
FileDBMgr->closeRNoSql();
 
사진 삭제

사진 설명을 입력하세요.

8. 데이터 바인딩

여기서는 insert를 사용 할 것인데, 다음과 같이 사용 하면 된다.

nline void insertInfo(sqlite3 *ptrSqlite, sqlite3_stmt *stmt, const std::string key, const std::string value)
{
	
    std::vector<std::string> output 
      = UtilW32::split(value, '\\');
	
	string atch_fle_nm_kor, atch_fle_path, atch_fle_py_nm, path_tmp;
	
	cmp_cod = output.at(1);
	std::size_t found = value.find_last_of("/\\");
	//마지막은 파일 이름이라고 생각하고 짤라 준다.	
	atch_fle_path = value;
	atch_fle_path = value.substr(0,found);
	atch_fle_nm = value.substr(found+1);
	//한글의 경우에는 만들어진 sqlite 데이터베이스 문자셑이
    //UTF-8 이므로 CP949에서 UTF-8로 변환 해 준다.
	atch_fle_nm_kor 
     = UtilW32::convert(atch_fle_nm.c_str(), "CP949", "utf-8");
	atch_fle_py_nm = atch_fle_nm_kor;
	//UTF-8에서 한글 변환
	path_tmp = UtilW32::convert(atch_fle_path.c_str(), "CP949", "utf-8");
	
	if(bind_str(ptrSqlite, stmt, 1,  reinterpret_cast<const char*>(key.c_str()) ) == false)
		{ LOG_TRACE(LOG_ERROR, "\nFail to insert column 1: %s => %s\n", sqlite3_errmsg(ptrSqlite), key.c_str());}
	if(bind_str(ptrSqlite, stmt, 2,  reinterpret_cast<const char*>(cmp_cod.c_str()) ) == false)
		{ LOG_TRACE(LOG_ERROR, "\nFail to insert column 2: %s => %s\n", sqlite3_errmsg(ptrSqlite), cmp_cod.c_str());}
	//제대로 수행 했는 지 알아본다.
	if (sqlite3_step(stmt) != SQLITE_DONE) {
		LOG_TRACE(LOG_ERROR, "Could not step (execute) rows stmt: %s\n", sqlite3_errmsg(ptrSqlite));
	}
	//바인딩 했던 변수들을 모두 정리 해주는 작업
	sqlite3_clear_bindings(stmt);
	sqlite3_reset(stmt);
	
	return;
}
 

:bind_str 함수

bool bind_str(sqlite3 *db, sqlite3_stmt *stmt, int index, const char *pstr)
{
	int sz = strlen(pstr);
	
	if (sqlite3_bind_text (
			stmt, index,  // Index of wildcard
    		pstr, sz,  // length of text
    		SQLITE_STATIC
		)!= SQLITE_OK
	){
		return false;
	}
	
	return true;
}
 
 

이상으로 sqlite과 Nosql 데이터베이스인 kyotocabinet를 사용하는 법에 대해서 알아봤다.

 

 

 

728x90