병렬 프로그래밍 PPT

Advertisements

ARMCC 에서 C++ / C Mix 하기

간단한건데 고생해서 ㅠ_ㅠ

1. c 에서 c++ 함수를 부르기.. 객체 부르기는 실패..

[c file]

int main() {
   entry_for_cpp();
}

[c++ file]

extern "C" int entry_for_cpp(void)
{
}

2. c++ 에서 c 함수 부르기..
(주) c파일은 header 파일을 만들지 않는다

[c++ file]

extern "C" void Set_Timer3_PWM1(int value);
   void RealHardware::SetMotor(int motor, int value) {
   Set_Timer3_PWM1(value);
}

[c file]

void Set_Timer3_PWM1(int value)
{
}

Visual Studio 내 입맛대로 설정!

  1. 라인 번호 보이기

Tools > Options > Text Editor > All Language > Line Numbers

  1. 파일 저장을 UNIX 타입 & UTF-8로 하기

File > Advanced Save Option

  1. 빨간줄 안보이게 하기

Tools > Options > Text Editor >C/C++ > Advanced > IntelliSense > Disable Squiggles

  1. Visual Assist 에서 80라인 선 보여주기

VAssist X Options > Advanced > Display > Display Indicator 머시기..

  1. Visual Assist 에서 spell 체커 해제 하기

VAssist X Options > Advanced > Underline > Underline spelling 머시기…

또 뭐있나..

stdout redirect


#include 

#include 

#include 



#define MAX_LEN 1024



int main(void)

{

  char buffer[MAX_LEN+1] = {0};

  int out_pipe[2];

  int saved_stdout;



  saved_stdout = dup(STDOUT_FILENO);  /* save stdout for display later */



  if( pipe(out_pipe) != 0 ) {          /* make a pipe */

    exit(1);

  }



  dup2(out_pipe[1], STDOUT_FILENO);   /* redirect stdout to the pipe */

  close(out_pipe[1]);



  /* anything sent to printf should now go down the pipe */

  //printf("ceci n'est pas une pipe");

  system("adb shell ls");

  fflush(stdout);



  read(out_pipe[0], buffer, MAX_LEN); /* read from pipe into buffer */



  dup2(saved_stdout, STDOUT_FILENO);  /* reconnect stdout for testing */

  printf("read: %sn", buffer);



  return 0;



}

C#(System.Data.SQLite)용 SQLite의 DataType

c#으로 SQLite만지작 하다가 자꾸 Value was either too large or too small for an Int32 이런 에러나 가서 문서를 찾아보니

테이블을 생성할때 “INT”로 만들면 32비트용, “INTEGER”로 만들면 64비트용 –_–;; 헐 Native SQLite도 그런가?

어쨌든, 아래는 C# SQLite DataType목록이다.

Since the SQLite engine is inherently typeless and ADO.NET is much more strongly typed, the ADO.NET wrapper must make certain decisions about the columns returned in any given SQL query. One of the deciding factors is the underlying datatype declared in the CREATE TABLE statement.

The following lists the datatypes and mappings the SQLite ADO.NET wrapper understands. If there is anything missing, wrong, or needs adding, please let me know:

COUNTER DbType.Int64

AUTOINCREMENT DbType.Int64

IDENTITY DbType.Int64

LONG DbType.Int64

TINYINT DbType.Byte

INTEGER DbType.Int64

INT DbType.Int32

VARCHAR DbType.String

NVARCHAR DbType.String

CHAR DbType.String

NCHAR DbType.String

TEXT DbType.String

NTEXT DbType.String

STRING DbType.String

DOUBLE DbType.Double

FLOAT DbType.Double

REAL DbType.Single

BIT DbType.Boolean

YESNO DbType.Boolean

LOGICAL DbType.Boolean

BOOL DbType.Boolean

NUMERIC DbType.Decimal

DECIMAL DbType.Decimal

MONEY DbType.Decimal

CURRENCY DbType.Decimal

TIME DbType.DateTime

DATE DbType.DateTime

TIMESTAMP DbType.DateTime

DATETIME DbType.DateTime

BLOB DbType.Binary

BINARY DbType.Binary

VARBINARY DbType.Binary

IMAGE DbType.Binary

GENERAL DbType.Binary

OLEOBJECT DbType.Binary

GUID DbType.Guid

UNIQUEIDENTIFIER DbType.Guid

MEMO DbType.String

NOTE DbType.String

LONGTEXT DbType.String

LONGCHAR DbType.String

SMALLINT DbType.Int16

BIGINT DbType.Int64

LONGVARCHAR DbType.String

SMALLDATE DbType.DateTime

SMALLDATETIME DbType.DateTime

C#(System.Data.SQLite) vs CSharpSqlite

SQLite에서 정식으로 배포되는 System.Data.SQLite 버전의 C# SQLite DLL이 있고,

다른 곳에서 독자적으로 개발하는 CsharpSqlite DLL이 있는데, 코드 수준에서 호환되지는 않는다.(하지만 마이그레이션 한다고 하면 크게 고칠곳은 없다)

http://code.google.com/p/csharp-sqlite/wiki/Benchmarks

위 싸이트 벤치마킹에 따르면 정식 DLL보다 iterating에서 CshartSqlite DLL이 20~40%정도 빠르다! 라고 자랑하고 있는데..

나는 Insert,Update는 느려도 되니까 이걸로 써야겠다! 라고 생각하고 도입했는데 결과는 더 느리다 ㅠ_ㅠ

원인은, 벤치마킹에 사용한 SQLite 정식 DLL의 Method가 GetValues라는 함수 인데, 이 함수 자체가 느리다.

정식 DLL에서 GetValues함수를 쓰지 않고, GetInt32() 나 GetDouble()로 일일이 지정해 줘서 쓰게 되면

CsharpSqlite 보다도 iteration 속도가 빠르게 나오는 것을 확인했다.

결과적으로 헛짓했지만, 아쉬운건 지금 100만건 iteration하는데 (Row당 Column개수가 8개임을 고려), 무려 4.8초나 걸린다 ㅠ_ㅠ

이거보다 좀 더 빠르게 하는 방법이 없을까나..

네트워크 드라이브에 있는 VS Project열기

보안 문제 때문에, 네트워크 드라이브를 통해서 비주얼 스튜디오 프로젝트 파일을 열면

DLL파일을 읽을 수 없다는 에러를 만난다.

해결 방법은 http://msdn.microsoft.com/en-us/library/dd409252.aspx 를 참고 하면 된다.

요약하자면,

요 내용이 아래 파일 안에 추가되어야 한다.

C:Program FilesMicrosoft Visual Studio 10.0Common7IDEdevenv.exe.config

Poco lib를 이용한 SQLite 사용하기

SQLite를 통해서 C++ 프로그램에서 SQLite를 접근하는 방법에 대한 문서이다

Poco Library는?

SQLite은 C기반이기 때문에 객체기반이지 않아서, 객체로 랩핑한 라이브러리가 있을거라는 예상하에 구글링을 했다.

다양한 라이브러리가 나왔는데, 다들 장단점이 있었다. 그 중에서 Poco라이브러리는 SQLite뿐만 아니라, MySQL, Oracle도

같은 형식으로 랩핑을 하고 있어서, 타 DBMS로 이전시 용이하고, 통일된 인터페이스를 제공하고 있었다.

또한 공짜 ( 사실 라이센스가 조금 복잡한데, 그냥 패스 -_- )이고, DB 랩핑 말고도 다른 부가적인 멋진 기능들을 같이 묶어놓았다.

단점이라면, 플랫폼 수준의 기능을 제공하는 미들웨어 같은 느낌이라, 덩치가 크다.

아래 문서는 Podo Doc을 한글로 바꾸고 정리한 내용이므로 자세한 내용은 http://pocoproject.org/docs/ 를 참고하면된다

예제 살펴보기

Poco Data는 Poco 데이터베이스 추상 레이어로 서로 다른 다양한 데이터 베이스의 데이터를 저장/읽기를 쉽게 해준다.아래는 기본 예제이다.

#include "Poco/Data/Common.h"
#include "Poco/Data/SQLite/Connector.h"
#include <iostream>

using namespace Poco::Data;

void init()
{
    SQLite::Connector::registerConnector();
}

void shutdown()
{
    SQLite::Connector::unregisterConnector();
}

int main(int argc, char* argv[])
{
    init();
    Session ses("SQLite", "sample.db");
    int count = 0;
    ses << "SELECT COUNT(*) FROM PERSON", into(count), now;
    std::cout << "People in DB " << count;
    shutdown();
}

위 예제는 보여주기 위한 것이다. Poco/Data/Common.h 파일은 인클루드 해주자. SQLite::Connector는 SQLite Connector를 등록하는데 사용된다. 이걸 해주어야 나중에 SQLite Session을 SessionFactory로 부터 생성할 수 있게 해준다. 생성자는 2개의 파라미터가 필요하다

Sesssion ses(“SQLite”, “sample.db”);

위 코드는 아래 코드와 동일하다

Session ses(SessionFactory::instance()::create(“SQLite”, “sample.db”));

<< 오퍼레이터는 SQL statements 를 Session으로 보내는데 사용된다. into(count) 는 쿼리의 결과가 어디에 저장되어야 하는지를 간단하게 session에게 알려준다. SQL statement의 마지막에 now라는 것을 주목하라. 이것을 집어 넣지 않으면 SQL 구문은 실행되지 않는다.

 

세션 생성하기

세션은 항상 SessionFactory create 메소드를 통해서 생성된다. 또는 암시적으로 Session 생성자의 2개의 파라미터를 통해서 생성된다.

데이터 추가하기 / 읽어오기

우선 아래와 같은 DB Table이 하나 있다고 가정하자.

ForeName (Name VARCHAR(30))

만약 1개의 데이터를 집어 넣으려고 한다면 간단하게 아래 처럼 하면 된다.

std::string aName(“Peter”);
ses << “INSERT INTO FORENAME VALUES(” << aName << “)”, now;

글쎄… 우리는 위에 처럼 할수 있지만, 우리가 원하는 건 아닐것이다. 더 좋은 솔루션은 placeholder를 사용하는 것이다. placeholder는 이름 앞에 : 를 붙여서 표현한다. 위의 코드를 placeholder를 활용한 코드로 다시 작성해보자.

std::string aName(“Peter”);
ses << “INSERT INTO FORENAME VALUES(:name)”, use(aName), now;

이 예제에서 :name이 Peter 값와 일치하도록 표현되고 있다. 위 예제는 placeholder를 사용하고 있지만, 진정한 placeholder의 장점 ( 성능 개선 )을 보여주고 있지 않는다. Statements 섹션을 읽어보면 좀 더 알 수 있다.

데이터베이스로 부터 데이터를 읽어오는 작업도 비슷하다. into 문법은 데이터베이스로 부터 리턴된 값을 c++ 객체에 넣도록 해준다. into는 기본값을 가질 수 있는데, 데이터베이스로 부터 null 값이 리턴이 되면 기본값을 가지도록 할 수 있다.

std::string aName;
ses << “SELECT NAME FROM FORENAME”, into(aName), now; // the default is the empty string
ses << “SELECT NAME FROM FORENAME”, into(aName, “default”), now;
into 와 use 문법을 같이 사용하는 것도 가능하다std::string aName;
std::string match(“Peter”)
ses << “SELECT NAME FROM FORENAME WHERE NAME=:name”, into(aName), use(match), now;
poco_assert (aName == match);

일반적으로, 테이블 구조는 위에 처럼 간단하지 않다. 보통 여러개의 컬럼을 가지고 있다. 따라서 여러개의 into/use를 사용해야 한다. 아래 예제는 Person 테이블이 age, firstname, lastname을 가지고 있다고 가정한다.

std::string firstName(“Peter”);
std::string lastName(“Junior”);
int age = 0;
ses << “INSERT INTO PERSON VALUES (:fn, :ln, :age)”, use(firstName), use(lastName), use(age), now;
ses << “SELECT (firstname, lastname, age) FROM Person”, into(firstName), into(lastName), into(age), now;

여기에서 가장 중요한 점은 into 와 use 수식이 사용된 순서이다. 처음 나온 placeholder는 처음에 위치한 use와 매치된다. 두번째 placeholder는 두번째 use와 매치된다. 이것은 into 수식에서도 동일하게 적용된다. 예제에서 우리는 firstname을 첫번째 컬럼으로 지정했고 따라서 이것은 into(fitstName)으로 들어가게 된다.

NULL 엔트리 핸들링하기

데이터베이스에서 일반적인 경우로 optinal data field가 NULL을 담고 있는 경우가 있다. NULL을 수용하기 위해서는 into 문법은 항상 defalut 값을 가지고 있어야 한다. 예를 들어서, age 가 optional field라고 가정하고, 기본값으로 -1을 가지도록 한다면, into(age, -1) 이라고 적으면 된다.

std::string firstName(“Peter”;
std::string lastName(“Junior”);
int age = 0;
ses << “INSERT INTO PERSON VALUES (:fn, :ln, :age)”, use(firstName), use(lastName), use(age), now;
ses << “SELECT (firstname, lastname, age) FROM Person”, into(firstName), into(lastName), into(age, -1), now;

statements로 동작하기

우리는 위에서 자주 statment를 언급했었다. 아직 우리는 session 객체로 동작시키는 법만 알고 있었다. 사실 우리는 이미 statments를 이용해서 동작시키고 있었다. 여기서 session의 << 오퍼레이션의 정의를 살펴보자.

template
Statement Session::operator << (const T& t)

위 코드에서 보는 것처럼 << 오퍼레이터는 내부적으로 Statement를 생성하고, 리턴하고 있음을 알 수 있다. 기존에 살펴본 예제에서는 리턴된 statement는 다른 변수에 다시 저장되지 않고, now 문법 때문에 곧바고 수행되고 있었다. 그리고나서 statement는 destroy 되었다. 이제 예전 방식을 statement에 assign하는 것으로 변경해보자.

std::string aName(“Peter”);
Statement stmt = ( ses << “INSERT INTO FORENAME VALUES(:name)”, use(aName) );

소괄호를 둘러싼것을 주목하라. 이렇게 하지 않으면 컴파일러가 에러를 발생시킨다. 만약 위의 문법이 맘에 들지 않는다면, 아래의 코드도 동일한 효과를 낸다.

Statement stmt(ses);
stmt << “INSERT INTO FORENAME VALUES(:name)”, use(aName);
위에 처럼 하면 변수에 값이 저장이 될까? 그렇지 않다. 이제부터는 실행과 제어가 분리되어 있다.
std::string aName(“Peter”);
Statement stmt = ( ses << “INSERT INTO FORENAME VALUES(:name)”, use(aName) );
stmt.execute();
poco_assert (stmt.done());

execute()함수를 호출함으로써 SQL 문법은 실행이 된다. stmt.done() 함수를 통해서 간단하게 잘 수행되었는지를 확인할 수 있다.

준비된 Statements

statement 준비는 now 문법을 제외시키는 것 외에는 동일하다.

Statement stmt = ( ses << “INSERT INTO FORENAME VALUES(:name)”, use(aName) );

준비된 statements를 사용하는 이점은 성능이다. 아래 예제를 보자.

std::string aName();
Statement stmt = ( ses << “INSERT INTO FORENAME VALUES(:name)”, use(aName) );
for (int i = 0; i < 100; ++i)
{
aName.append(“x”);
stmt.execute();
}

SQL 쿼리를 100회를 파싱하고 생성하는 대신에, 오직 한번만 생성하고 placeholder 와 use 문법의 조합으로 인해 100개의 다른 값을 데이터베이스에 넣을수가 있었다. 하지만 여전히 위 예제는 values of collection을 데이터베이스에 집어 넣는 최고의 방법은 아니다.

하지 말아야 할 것

use문법은 reference 변수를 입력으로 받아서, 나중에 execute()가 수행될 때 처리된다. 따라서 오직 변수만을 사용할 수 있으며, 상수를 사용할 수 없다. 아래 코드는 실패할 것이다.

Statement stmt = (ses << “INSERT INTO PERSON VALUES (:fn, :ln, :age)”, use(“Peter”), use(“Junior”), use(4)); //ERR!
stmt.execute();

콜렉션 지원

만약 한번에 많은 변수를 핸들링할 필요가 있다면, collection 클래스를 사용하는 것이 방법이다. 기본적으로 아래와 같은 collection type을 지원한다.

vector: 필요한 사항 없음
set: < 오퍼레이터는 반드시 데이터 형식에 의해 지원되어야 한다. 중복된 key/value는 무시된다.
multiset: < 오퍼레이터는 반드시 데이터 형식에 의해 지원되어야 한다.
map: () 오퍼레이션은 반드시 데이터 형식에 의해 지원되어야 하고, 객체의 키값을 리턴해야 한다. 중복되는 key/value값은 무시된다.
multimap : () 오퍼레이션은 반드시 데이터 형식에 의해 지원되어야 하고, 객체의 키값을 리턴해야 한다.

벡터를 이용한 대량으로 삽입하는 예제이다.

std::string aName(“”);
std::vector data;
for (int i = 0; i < 100; ++i)
{
aName.append(“x”);
data.push_back(aName);
}
ses << “INSERT INTO FORENAME VALUES(:name)”, use(data), now;

동일한 예제가 set, multiset에도 적용이 된다. 하지만 map과 multimap은 ()오퍼에이터가 없어서 적용되지 않는다.

use 문법이 비어있지 않는 collection만을 처리한다는 점을 기억하라.

아래 예제를 살펴보자.

std::string aName;
ses << “SELECT NAME FROM FORENAME”, into(aName), now;

이전에, 1개의 엔트리만을 담고 있기 때문에 위의 코드가 동작하는 것을 알 수 있었다. 하지만 이제는 데이터베이스 테이블이 최소한 100개의 스트링을 담고 있다. 위 코드는 단지 1개의 결과값만을 저장할 수 있는 저장공간을 제공한다. 따라서 위 코드는 exception을 발생시킬 것이다. 아래 예제는 해결 방법중 하나이다.

std::vectornames;
ses << “SELECT NAME FROM FORENAME”, into(names), now;

limit 구문

collection을 이용한 동작은 대량의 데이터를 처리하게 될것이고, 동시에 대량의 데이터 처리는 어플리케이션을 오랜 시간 동안 block상태로 만들어 버릴것이다. limit 키워드를 사용하면 문제를 해결 가능 하다.

데이터베이스에서 수천 row를 가져와서 GUI에 그린다고 가정하자. 사용자는 언제나 데이터를 가져오는 것을 정지할 수 있다. 이럴경우 우리는 아래처럼 프로세스를 분리해야 한다.

std::vectornames;
ses << “SELECT NAME FROM FORENAME”, into(names), limit(50), now;

위 예제는 50개의 row만을 데이터베이스에서 가져와서 저장하는 예제이다.
만약 names collection이 비어있지 않았었는데, 그 안에 정확히 50개의 데이터만을 담도록 하고 싶다면 limit 파라미터의 2번째를 true로 해주어야 한다. (기본적으로는 false)

std::vector names;
ses << “SELECT NAME FROM FORENAME”, into(names), limit(50, true), now;

statement.done()이 true를 리턴할 때 까지 collection을 반복한다. 아래 예제는 테이블에 101개의 데이터가 들어있다고 가정한다.

std::vectornames;
Statement stmt = (ses << “SELECT NAME FROM FORENAME”, into(names), limit(50));
stmt.execute(); //names.size() == 50
poco_assert (!stmt.done());
stmt.execute(); //names.size() == 100
poco_assert (!stmt.done());
stmt.execute(); //names.size() == 101
poco_assert (stmt.done());

위에서 우리는 데이터 없음을 리턴하는 것도 정상인것을 가정했다. 아래처럼 실행하면 테이블이 비어있는 경우에도 잘 동작을 한다.

std::string aName;
ses << “SELECT NAME FROM FORENAME”, into(aName), now;

최소한 1개 이상의 데이터가 있어야 됨을 보장하려면 lowerLimit을 걸면 된다.

std::string aName;
ses << “SELECT NAME FROM FORENAME”, into(aName), lowerLimit(1), now;

만약 테이블이 비어있다면, exception이 발생하게 된다. 한개씩 결과를 계속 뽑아내고 싶다면, 예를 들어 collection을 사용하고 싶지 않다면, 아래 처럼 작성하면 된다.

std::string aName;
Statement stmt = (ses << “SELECT NAME FROM FORENAME”, into(aName), lowerLimit(1), upperLimit(1));
while (!stmt.done())
stmt.execute();

또다른 방법은 range를 이용하는 것이다.

std::string aName;
Statement stmt = (ses << “SELECT NAME FROM FORENAME”, into(aName), range(1,1));
while (!stmt.done())
stmt.execute();

복잡한 데이터 형식 매핑

위에서 살펴본 모든 예제는 기본 데이터 형식을 가지고 작업하는 것이었다. 하지만 현실에서는 그렇지 못하다. 여기서는 당신이 Person class를 가지고 있다고 가정하자.

class Person
{
public:
    // default constructor+destr.
    // getter and setter methods for all members
    [...]

    bool operator <(const Person& p) const
        /// we need this for set and multiset support
    {
        return _socialSecNr < p._socialSecNr;
    }

    Poco::UInt64 operator()() const
        /// we need this operator to return the key for the map and multimap
    {
        return _socialSecNr;
    }

private:
    std::string _firstName;
    std::string _lastName;
    Poco::UInt64 _socialSecNr;
}

필요한 것은 TypeHandler 템플릿의 형식에 맞춰 template specialization 해주는 것이다. 주의할 점은 템플릿 specialization은 반드시 original template와 같은 namespace에 존재 해야 한다는 점이다(Poco::Data). template specialization은 반드시 아래 메소드들을 구현해주어야 한다.

namespace Poco {
namespace Data {

template <>
class TypeHandler<class Person>
{
public:
    static std::size_t size()
    {
        return 3; // we handle three columns of the Table!
    }

   static void bind(std::size_t pos, const Person& obj, AbstractBinder* pBinder)
    {
        poco_assert_dbg (pBinder != 0);
        // the table is defined as Person (FirstName VARCHAR(30), lastName VARCHAR, SocialSecNr INTEGER(3))
        // Note that we advance pos by the number of columns the datatype uses! For string/int this is one.
        TypeHandler<std::string>::bind(pos++, obj.getFirstName(), pBinder);
        TypeHandler<std::string>::bind(pos++, obj.getLastName(), pBinder);
        TypeHandler<Poco::UInt64>::bind(pos++, obj.getSocialSecNr(), pBinder);
    }

    static void prepare(std::size_t pos, const Person& obj, AbstractPreparation* pPrepare)
    {
        poco_assert_dbg (pBinder != 0);
        // the table is defined as Person (FirstName VARCHAR(30), lastName VARCHAR, SocialSecNr INTEGER(3))
        // Note that we advance pos by the number of columns the datatype uses! For string/int this is one.
        TypeHandler<std::string>::prepare(pos++, obj.getFirstName(), pPrepare);
        TypeHandler<std::string>::prepare(pos++, obj.getLastName(), pPrepare);
        TypeHandler<Poco::UInt64>::prepare(pos++, obj.getSocialSecNr(), pPrepare);
    }

    static void extract(std::size_t pos, Person& obj, const Person& defVal, AbstractExtractor* pExt)
        /// obj will contain the result, defVal contains values we should use when one column is NULL
    {
        poco_assert_dbg (pExt != 0);
        std::string firstName;
        std::string lastName;
        Poco::UInt64 socialSecNr = 0;
        TypeHandler<std::string>::extract(pos++, firstName, defVal.getFirstName(), pExt);
        TypeHandler<std::string>::extract(pos++, lastName, defVal.getLastName(), pExt);
        TypeHandler<Poco::UInt64>::extract(pos++, socialSecNr, defVal.getSocialSecNr(), pExt);
        obj.setFirstName(firstName);
        obj.setLastName(lastName);
        obj.setSocialSecNr(socialSecNr);
    }
};
} } // namespace Poco::Data

이것이 당신이 해야할 모든 작업이다. 이제 아래처럼 간단하게 Person을 사용하면 된다.

std::mappeople;
ses << “SELECT * FROM Person”, into(people), now;

RecordSet

Poco::Data::RecordSet class는 데이터베이스 테이블과 같이 동작하는 일반적인 방법을 제공한다. RecordSet을 이용하면 아래 사항이 가능하다.

모든 column과 row의 interation
column에 대한 메타 데이터를 담는다.(이름, 형식, 길이 등등)

RecordSet을 쓰려면, 첫번째로 Statement를 생성하고, 실행한 후 Statement로 부터 RecordSet를 생성한다. 예제이다.

Statement select(session);
select << “SELECT * FROM Person”;
select.execute();
RecordSet rs(select);

아래 예제는 어떻게 모든 row와 column을 처리할 수 있는지를 보여준다.

bool more = rs.moveFirst();
while (more)
{
for (std::size_t col = 0; col < cols; ++col)
{
std::cout << rs[col].convert() << ” “;
}
std::cout << std::endl;
more = rs.moveNext();
}

이 예제는 limit과 같이 조합해서 사용하는 예제이다.

Statement select(session);
select << “SELECT * FROM Person”, range(0, 10);
RecordSet rs(select);
while (!select.done())
{
select.execute();
bool more = rs.moveFirst();
while (more)
{
for (std::size_t col = 0; col < cols; ++col)
{
std::cout << rs[col].convert() << ” “;
}
std::cout << std::endl;
more = rs.moveNext();
}
}

Tuples

Poco::Tuple 과 Poco::Tuple의 vector는 column 타입들을 이미 알고 있을 경우 간편한 방법을 제공한다.아래 코드를 살펴보자.

typedef Poco::Tuple Person;
typedef std::vector People;

People people;
people.push_back(Person(“Bart Simpson”, “Springfield”, 12));
people.push_back(Person(“Lisa Simpson”, “Springfield”, 10));

Statement insert(session);
insert << “INSERT INTO Person VALUES(:name, :address, :age)”,
use(people), now;

아래 코드도 가능하다

Statement select(session);
select << “SELECT Name, Address, Age FROM Person”,
into(people),
now;

for (People::const_iterator it = people.begin(); it != people.end(); ++it)
{
std::cout << “Name: ” << it->get() <<
“, Address: ” << it->get() <<
“, Age: ” << it->get() < 11.}

Session Pooling

데이터베이스와 연력을 생성하는 작업은 시간을 잡아먹는 작업이다. 따라서 session객체를 다 쓰면 반환받았다가 나중에 다시 써먹는 것은 좋은 방법이다. Poco::Data::SessionPool 은 session 모음을 관리해준다.

SessionPool pool(“ODBC”, “…”);
// …
Session sess(pool.get());

session이 destroy될 때 자동으로 Pool로 반환을 한다.