C++/STLでODBC

C++でDBへアクセスするにはMFCだの、ADOだのややこしいライブラリをリンクするか、黙ってCで記述(各DBのライブラリを直接呼び出すコードを記述)するか、マネージドコードの仲間入りになるかになる。
最近流行りの言語(PHPとか)はあっさりDBをサポートしているのにC++/STLでさくっとSQLを書きたい場合、結構骨が折れる。
と言う訳で、なんちゃってodbcクラスを作りました。
以下のようにSQLが発行できちゃいます。

  db, "INSERT INTO test( c1, c2) VALUES(?,?)", "test", 100, endsql;
ぱっと見、何がなんだか分からないかもしれませんが、キモはSQL文に続けてパラメータが記述できる点で、結構楽にSQLが発行できます。
(見る人が見れば凶悪な演算子のオーバーロードに見えるかもしれないが・・・)
ちなみに、様々なDBに対応する為と、Linuxへの移植性を考えてODBCにしました。
ダウンロード(2011/04/15 SourceForgeにプロジェクトを作成しました)
2008-03-11 | コメント:5件



C++/STLで正規表現

今まで正規表現を使いたい場合、とっとと別の言語に切り替えていた私ですが、Boostというライブラリの正規表現パッケージを使ってみました。Boostのサイトにはサンプルはあるのですが、C++/STLでさくっと正規表現を使うにはイマイチ感があったので、覚書ということでサンプルのせます。ちなみに、Boostのインストール等の情報はLet's Boostがお勧めです。
若干ですがコードの説明を、サンプルはHTTPのレスポンスヘッダ(WEBサーバーからの戻りヘッダ)からCookie情報を取得するものです。関数 boost::regex_search が正規表現を使って文字列の検索を行っています。
その他、正規表現の利用法として入力値のチェックもあるかと思います。その場合、boost::regex_matchという関数が使えます。

#include <boost/regex.hpp>
#include <iostream>
int main(int , char* [])
{
  // 検索対象文字列
  std::string str( "HTTP/1.1 200 OK\r\n"
  "Server: Apache\r\n"
  "Set-Cookie: NAME1=VAL1\r\n"
  "Set-Cookie: NAME2=VAL2; expires=Mon, 18-02-2008 23:30:45 GMT\r\n"
  "Set-Cookie: NAME3=VAL3; path=path\r\n"
  "Set-Cookie: NAME4=VAL4; path=path; domain=example\r\n"
  "Set-Cookie: NAME5=VAL5; path=path; domain=example; secure\r\n"
  "Connection: close\r\n"
  "Content-Type: text/html\r\n");
  // 正規表現
  boost::regex r(
    "^Set-Cookie:\\s*([^;$\\s]+);?(?:\\s*expires=([^;$]+);?)?"
    "(?:\\s*path=([^;$\\s]+);?)?(?:\\s*domain=([^;$\\s]+);?)?"
    "\\s*(secure)?\\s*$"
    );
  boost::smatch what;  // マッチ文字列参照オブジェクト
  std::string::const_iterator start = str.begin();
  std::string::const_iterator end = str.end();
  // 検索対象の文字列から正規表現にマッチする文字列(複数有)を取り出す
  while ( boost::regex_search(start, end, what, r) ) {
    // 取得した文字列をstringに代入する(smatchにはイテレーターが入る)
    std::string cookie(what[1].first, what[1].second);
    std::string expires(what[2].first, what[2].second);
    std::string path(what[3].first, what[3].second);
    std::string domain(what[4].first, what[4].second);
    std::string secure(what[5].first, what[5].second);
    std::cout << cookie << ":" << expires << ":" << path << ":"
              << domain << ":" << secure  << ":" << std::endl;
    start = what[0].second;  // 次のマッチ文字列を取得する
  }
   return 0;
}
2008-02-20 | コメント:0件



CのsprintfをC++/STLで実現する

今まで避けて通ってきた道でしたが、C++でsprintfを使うには少々違和感があった。
STLのstringクラス を使うようになり、『やっぱstrstreamか』と思った時期もあったが、最近、Rubyでプログラムを組む機会があり、あっさりとsprintfがサポートしているのを見て、stringクラスを返すsprinfのようなものがあってもよいなと思い直し作成した。

/**********************************************************************
 CのsprintfをC++/STLで実現する
 使い方
    std::string str = cformat( "%d:%s", intvalue, charpointer);
 試したコンパイル環境
    VC++ .NET 2003 / WINDOWS XP Professional 64 bit edition.
    GCC C++ 3.3.6 / glibc 2.3.4 / Vine Linux 4.2
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <vector>
#include <string>
#include <stdexcept>
#ifdef _WIN32
#define vsnprintf   _vsnprintf
#endif
std::string cformat( char *format, ...)
{
    int bufsize = 1024; // 適当なサイズ
    std::vector<char>   buff(bufsize);
    va_list args;
    // 適当なバッファサイズで先ずは、vsnprintfを試す。
    // 出力がバッファサイズ以上の場合、VC++ .NET 2003の場合は -1、
    // glibc2.1以降は、書き込みに必要なサイズを返す。
    va_start(args, format);
    int vssize = vsnprintf( &buff[0], bufsize, format, args);
    va_end(args);
    // vsnprintfが成功した場合終了する。
    if ( vssize >= 0 && vssize < bufsize ) {
        buff.resize(vssize);
        return std::string( buff.begin(), buff.end() );
    }
#ifdef _WIN32
    // VC++ .NET 2003 書き込みに必要なサイズを取得する。
    va_start(args, format);
    vssize = _vscprintf( format, args);
    va_end(args);
#endif
    if ( vssize < 0 ) throw std::runtime_error(format);
    // サイズを再割り当てし、再度試す
    buff.resize(vssize + 1);
    va_start(args, format);
    vssize = vsnprintf( &buff[0], vssize + 1, format, args);
    va_end(args);
    if ( vssize < 0 ) throw std::runtime_error(format);
    buff.resize(vssize);
    return std::string( buff.begin(), buff.end() );
}
2008-02-14 | コメント:2件



resolv.confには生きているサーバーを指定しよう。

会社のWEBサーバーの応答が悪くなったので、対応に迫られた。
会社のWEBサーバーは2段構えになっていて、フロントのWEBサーバーからmod_rewriteを使って、バックのアプリケーションサーバーに接続している。
このバックへ向かう接続が遅くなっていた。
『何が悪いのか?』と散々調べていたが、結論は、resolv.confに記載されているDNSサーバーにアクセスできなかった為、タイムアウト待ちが発生していた。
ちなみに、mod_rewriteの記述はIPアドレスで行っていたので、DNSサーバーは関係ないだろうと思っていたのが間違いであった。
DNSサーバーを立ち上げ、DNSサーバーのログを確認するとしっかりWEBサーバーからのアクセスが記録された。
 ということで、Linuxでネットワークの接続が遅いときは、resolv.confの設定を確認してみると幸せになれるかもしれません
2008-01-22 | コメント:0件
Previous Page | Next Page