Skip to main content

C++ of the Day #45 - SQLite3 C++ wrapper #3

이번엔 sqlite3++를 소개하는 마지막 시간으로 SQLite3의 extension 기능에 대한 부분을 살펴 보겠습니다.

SQLite3는 사용자가 정의할 수 있는 function과 aggregate들을 통해 기본 기능을 확장할 수 있도록 하고 있습니다. ((이외에 collation sequence라는 확장 기능도 있습니다만 sqlite3++에서는 지원하지 않습니다. 아직까지는...))

예를 들어 A라는 column의 정보를 가지고 B와 C의 데이터 중 선택할 수 있는 cond(A, B, C)라는 function을 사용자가 정의할 수 있다면 복잡한 SQL 구문 대신 다음과 같이 간단하게 사용할 수 있을 것입니다.

SELECT cond(A, B, C) FROM ...;


그리고 특정 규칙을 적용한 filter를 사용하여 해당 filter에 의해 선택된 항목들의 개수만 세고 싶다면 다음과 같은 aggregate를 만들어 사용할 수도 있습니다. 아래 코드에서는 count_of가 사용자가 정의한 filter라고 가정합니다.

SELECT count_of(A, B, C) FROM ...;


이처럼 function이나 aggregate는 SQLite3가 기본적으로 제공하지 않거나 SQL만으로 작성하기에는 복잡한 기능들을 사용자가 정의할 수 있도록 해줍니다.

그럼 sqlite3++을 사용하여 간단하게 이런 function이나 aggregate를 만들 수 있는 방법을 알아보겠습니다.

먼저 ext::function의 경우에는 function pointer나 functor, boost::binder 그리고 boost::lambda등을 function으로 등록하여 사용할 수 있습니다. 예를 들면 다음과 같습니다.

int plus100(int val) {
return val + 100;
}
// ...
sqlite3pp::ext::function func(db);
func.create("plus100", &plus100);

// SELECT plus100(id) FROM ...;


위의 plus100()은 단순히 입력된 값에 100이라는 값을 더하여 리턴하는 함수입니다. 등록은 ext::function 객체의 create 함수를 사용하며 template 인자의 문법은 boost::function과 유사하게 function type이 사용됩니다. :-)

이처럼 간단한 코드는 boost::lambda로도 등록하여 사용할 수 있습니다.

using namespace boost::lambda;
func.create("plus100", _1 + 100);


물론 다음과 같이 입력과 출력의 타입은 서로 다를 수 있으며 입력의 개수는 현재 0~5개까지 지원합니다.

int strlen_3(std::string const& s1, std::string const& s2, std::string const& s3)
{
return (s1 + s2 + s3).size();
}
// ...
func.create_function("strlen_3", &strlen_3);

// SELECT strlen_3(A, B, C) FROM ...;


위에서 본 코드와 같이 ext::function은 비교적 간단히 사용할 수 있습니다만 ext::aggregate의 경우에는 약간 복잡합니다. ext::aggregate는 하나의 함수가 아니라 해당 입력값을 하나씩 받아들이는 step()함수와 모든 입력이 끝난 뒤에 리턴값을 처리하는 finish()함수로 구성됩니다.

ext::function보다 복잡하다고는 하지만 실제 사용 방법은 간단하게 step()함수와 finish()함수를 가지는 클래스를 구현하는 것입니다.

struct strlen_all
{
strlen_all() : n_(0) {
}
void step(std::string const& s) {
n_ += s.size();
}
int finish() {
return n_;
}
int n_;
};
// ...
sqlite3pp::ext::aggregate aggr(db);
aggr.create("strlen_all");

// SELECT strlen_all(name) FROM table;


위의 ext::aggregate는 해당 column에 있는 문자열의 길이의 합을 리턴합니다.

등록시에 사용되는 create 함수의 template 인자의 구성은 가 됩니다. aggregate의 리턴 타입은 자동으로 finish() 함수의 리턴 타입으로 결정됩니다. 여기서도 입력의 개수는 현재 0~5개까지로 구현되어 있습니다.

이것으로 구현한 sqlite3++의 사용 방법에 대한 설명을 마치겠습니다. 오랫만에 코드에 template을 좀 썼더니 재밌네요. 기회가 되면 sqlite3++에 사용된 template 구현 방법에 대해 설명해 보도록 하겠습니다. :-)

sqlite3pp - Google Code에서 코드들과 간단한 사용 예제들을 보실 수 있습니다.

Comments

Popular posts from this blog

CodeHighlighter plugin test page.

This post is for testing CodeHighlighter plugin which uses GeSHi as a fontifier engine. ((Those code blocks are acquired from Google Code Search .)) ((For more supported languages, go CodeHighlighter plugin or GeSHi homepage.)) C++ (<pre lang="cpp" lineno="1">) class nsScannerBufferList { public: /** * Buffer objects are directly followed by a data segment. The start * of the data segment is determined by increment the |this| pointer * by 1 unit. */ class Buffer : public PRCList { public: Buffer() { ++index_; } PHP (<pre lang="php" lineno="4">) for ($i = 0; $i $value = ord( $utf8_string[ $i ] ); if ( $value < 128 ) { // ASCII $unicode .= chr($value); } else { if ( count( $values ) == 0 ) { $num_octets = ( $value } $values[] = $value; Lisp (<pre lang="lisp">) ;;; Assignment (define-caller-pattern setq ((:star var fo...

C++ of the Day #43 - SQLite3 C++ wrapper #1

The Definitive Guide to SQLite 를 읽다가 공부 겸 해서 C++ wrapper를 만들어 보았습니다. 최대한 C++ 냄새(?)가 나도록 만들어 보았습니다. :-) ((SQLite는 복잡한 관리가 필요없이 사용가능한, 파일이나 메모리 기반의, 라이브러리로 제공되는, 약 250kb 용량의, 대부분의 SQL92문을 지원하는, open source RDB입니다.)) 이 wrapper를 사용하기 위해서는 (당연하게도!) sqlite3 와 (당연하게도?) boost 라이브러리가 필요합니다. 사용 예들을 살펴보는 것으로 설명을 대신합니다. 이번 글에서는 다음과 같은 contacts 테이블이 test.db에 존재한다고 가정합니다. CREATE TABLE contacts ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT NOT NULL, UNIQUE(name, phone) ); Command 먼저 test.db 파일을 사용하기 위해 다음과 같이 파일 이름을 주어 connection 객체를 생성합니다. 생성과 동시에 test.db와 연결이 이루어집니다. ((생성자외에 open() 함수를 사용할 수도 있습니다.)) sqlite3pp::connection conn("test.db"); 다음은 contacts 테이블에 정보를 추가하는 가장 간단한 방법입니다. connection 클래스에서 제공하는 execute 함수를 사용합니다. ((executef 함수를 사용하면 printf와 같은 문법을 사용하여 query문을 작성할 수 있습니다.)) conn.execute("INSERT INTO contacts (name, phone) VALUES ('user', '1234')"); 위와 동일한 작업을 parameterized query를 사용하여 할 수도 있습니다. ((step()함수가 실제 query문을 수행하는 함수입니다. ...

Textiler plugin test page

This post is for testing Textiler plugin . This plugin uses Textile engine (version 2.0.0). The sample text is come from Textile test page. (Note that the result will be vary according to your CSS options.) Supported wiki syntax Rendering result h2{color:green}. This is a title h3. This is a subhead p{color:red}. This is some text of dubious character. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote. bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised. Simple list: #{color:blue} one # two # three Multi-level list: # one ## aye ## bee ## see # two ## x ## y # three Mixed list: * Point one * Point two ## Step 1 ## Step 2 ## Step 3 * Point three ** Sub point 1 ** Sub point 2 Well, that went well. How about we insert an <a href="/" title="watch out">old-fashioned hypertext link</a>? Will the quo...