MySQL APIのuse()にハマる

C++からMySQLデータベースにアクセスする際,主にMySQL++を使っています.
MySQL++: MySQL++

MySQL++ is a C++ wrapper for MySQL’s C API. It is built around the same principles as the Standard C++ Library, to make dealing with the database as easy as dealing with STL containers. In addition, MySQL++ provides facilities that let you avoid the most repetitive sorts of SQL within your own code, providing native C++ interfaces for these common tasks.

データベースからデータをSELECT文等で取り出す際,以前はなんでもstore()を使っていたのですが,
MySQL++: MySQL++

StoreQueryResult set type for "store" queries.

This is the obvious C++ implementation of a class to hold results from a SQL query that returns rows: a specialization of std::vector holding Row objects in memory so you get random-access semantics. MySQL++ also supports UseQueryResult which is less friendly, but has better memory performance. See the user manual for more details on the distinction and the usage patterns required.

と書いてあるので,use()の方を使ってみることにしました.
MySQL++: MySQL++

StoreQueryResult set type for "use" queries.

See the user manual for the reason you might want to use this even though its interface is less friendly than StoreQueryResult's.

あらかじめMAX_ROWの数だけ行のある(key, value)ペアのテーブルを作っておき,

  UseQueryResult results;
  Row row;
  for(int key=0;key<MAX_ROW;++key)
  {
     query<<"SELECT value FROM bench WHERE mykey="<<rand()%MAX_ROW;
     results = query.use();
     if(results)
     {
       row = results.fetch_row();
       cout<<"result of key["<<key<<"] = "<<row["value"]<<endl;
     }else
     {
       cout<<"cannot fetch results for key["<<key<<"]"<<endl;
       cout<<"reason:"<<query.error()<<endl;
     }
   } 

というプログラムをコンパイルして実行しました.

# icc bench.cc  -I/usr/local/include/mysql++/ -I /usr/local/mysql/include/ -lmysqlpp
# ./a.out
result of key[0] = val:3960886519
 terminate called after throwing an instance of 'mysqlpp::BadQuery'
   what():  Commands out of sync; you can't run this command now
 アボートしました 

....(泣)
store()を使うと,普通に動くんですけどねぇ.

  StoreQueryResult results;
  int success = 0;
  for(int key=0;key<MAX_ROW;++key)
  {
    Row row;
    query<<"SELECT value FROM bench WHERE mykey="<<rand()%MAX_ROW;
    results = query.store();
    if(results)
    {
      row = results.at(0);
      {
        cout<<"result of key["<<key<<"] = "<<row["value"]<<endl;
        ++success;
      }
    }else
    {
      cout<<"cannot fetch results for key["<<key<<"]"<<endl;
      cout<<"reason:"<<query.error()<<endl;
    }
  }

これをコンパイルして実行すると,

# ./a.out |head -10
result of key[0] = val:8841
result of key[1] = val:9924930093
result of key[2] = val:4928046
result of key[3] = val:080686
result of key[4] = val:91069
result of key[5] = val:273
result of key[6] = val:5618715
result of key[7] = val:5880
result of key[8] = val:3223180299386
result of key[9] = val:17513

答えは,MySQL C APIのドキュメントにありました.
MySQL :: MySQL 5.6 リファレンスマニュアル :: 23.8.7.72 mysql_use_result()

mysql_use_result()を使うとき、NULL値が戻されるまで、mysql_fetch_row()を実行しなければなりません。C APIは、これを行うのを忘れた場合、エラーCommands out of sync; you can't run this command nowを附与します。

あ...まさに,「Commands out of sync」エラーが...
よって,例えば次のように,「NULL値が戻されるまでfetch_rowする」ようにプログラムを書き換えますと,無事に動きました.

  UseQueryResult results;
  Row row;
  for(int key=0;key<MAX_ROW;++key)
  {
     query<<"SELECT value FROM bench WHERE mykey="<<rand()%MAX_ROW;
     results = query.use();
     if(results)
     {
       while(row = results.fetch_row())
       {
         cout<<"result of key["<<key<<"] = "<<row["value"]<<endl;
       }
     }else
     {
       cout<<"cannot fetch results for key["<<key<<"]"<<endl;
       cout<<"reason:"<<query.error()<<endl;
     }
   } 

store()とuse()で,利用方法によってパフォーマンスが変わるのか,とかベンチマークをする予定だったのですが,今日はここまでで力尽きました...続きは明日です.