Oracle、Postgres、MySQLなど、DBの種類は多数あります。

それらは、それぞれ、接続のためのコードの書き方が違います。ガーン


それらを吸収して、統一した書き方にしたいですよね?


こういう場合に良くやる手だとは思いますが、サンプルを書いてみようと思います。

また、例によって、コードのコピペの回数を減らすために、.hファイルと、.cppファイルを分けていません。

もっと本格的に遊んでみる場合には、宣言と実装を分けてくださいね。

(分けたサンプルは、この記事の一番下にリンクをつけましたので参考にしてみてください)



<前提>

ここでは、Postgresを例にとります。 OSはwindowsです。



<テーブル>

CREATE TABLE test
(
a int2 NOT NULL,
b1 int4,
b2 int8,
b4 varchar(10),
b5 float4,
b6 float8,
b7 date,
b8 timestamp,
CONSTRAINT pkey_t_test PRIMARY KEY (a)
)



<データ>

insert into test values(3, 1234,12345678, 'abcdef', 123.456, 1234567890.1
,'2008-04-07', '2008-04-07 11:12:15');




【準備】

以下の設定を事前にしてください。

1.「C++でPostgresと接続するには? 」を参照して、コンパイルの設定をしてください。

  もし、Dev-C++、VC++以外のコンパイラの場合は、「PostgreSQLの環境構築 」を参照して、

  makefileなどの設定を行ってください。


2.boostをインストールしてください。

  ファイルコピーするだけです。インストール方法は、こちら 。(簡単です!)




【サンプル】

#include <cstdlib>
#include <string>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <sys/types.h>



//こちらの記事 をコピーして以下のファイル名で保存してください
#include "Connection.h "


using namespace std;
using namespace boost;


//メイン
int main(int argc, char **argv)
{

    //DBの接続文字列(PQconnectdb参照 ) ↓のDBNAMEを作成したDB名に書きかえましょう
     string connStr("dbname=DBNAME user=postgres password=postgres");


    //接続クラス
     nana::ConnectionPtr connPtr;


     try{

        //Postgres接続用の接続クラスを作成する。
          connPtr = nana::createConnection("POSTGRES", connStr);

          connPtr->dbOpen();

        //
          char* strSQL = "select * from test";
          nana::RecordPtr rec = connPtr->query(strSQL);

          while(!rec->isEnd()){  
              cout
              << rec->getValue(0).getString() << " : "
              << rec->getValue(1).getString() << " : "
              << rec->getValue("b6").getString() << " : "
              << rec->getValue("b7").getTime().ctime() << " : "
              << rec->getValue("b8").getTime().ctime() << " : "
              << rec->getValue("b1").getInt() << endl;
              rec->moveNext();
          }


         rec->close();


         //トランザクションのサンプル
         /*connPtr->beginTransaction();
         int cnt = connPtr->execute("update test set a=0 where a=1");
         cout << "cnt=" << cnt << endl;
         //ロールバックしてみます。
         connPtr->endTransaction(false);
         */


     }catch(runtime_error& e){
         cout << e.what() << endl;
     }


     //DB接続を閉じます。
     if(connPtr.get() != NULL) connPtr->dbClose();


     system("PAUSE");
     return EXIT_SUCCESS;
}




【説明】

DBの種類を気にしなくても良いようにするためには、ヘッダファイルにPGconnなどのDB関連の型や関数が紛れ込まないことが重要になります。

もし紛れ込んでしまうと、必要なDBすべてのライブラリやヘッダファイルを用意しておかないとコンパイルできなくなります。(リンクエラーやインクルードファイルが見つからないエラーが起きます)


main.cppでincludeされているファイルを見てみてください!

本来Postgresと接続するときにincludeしなければならない、

"libpq-fe.h"がありません。


独自に作成したヘッダは"Connection.h"で

現状ではその中に"libpq-fe.h"はインクルードされていますが、これは.cppに持っていくことができます。


つまり、ヘッダとソースを.h、.cppファイルにそれぞれ分割すれば、"Connection.h"ファイルには一切、

DB関連の関数や変数が入りません。


これが、DBの種類を気にせずにコードを書くための1つ目の工夫です。



<DB関連の型や関数を紛れ込ませないもう一つの工夫>

それは、クラス設計です。

ConnectionクラスとRecordクラスがありますが、このクラスの引数や返り値の型には一切DB関連の型が紛れ込んでいません。

そして、main()をみると分かると思いますが、この2つのクラスしか使用していないですよね!



DB関連のものをすべてこの2つのクラスが隠蔽しているのです。





<コンパイル時に使用しないDBをコンパイルさせない工夫>

Connection.hを見てみてください。

先頭に、以下の定義があります。


#define USE_DB_POSTGRES


ファイルの最後に、以下の記述があります。


#ifdef USE_DB_POSTGRES
#include "PgConnection.h"
#endif


これは、「#define USE_DB_POSTGRES」の記述があるときにだけ、"PgConnection.h"を読み込みなさいとコンパイラに命令しているのです。






【拡張】

MySQLやOracleについても、ConnectionクラスとRecordクラスのサブクラスを作成して作ってみてください。

クラス名は、MySqlConnection、OracleConnectionにしましょう。

書き方は、Connection.hのPgConnectionクラスを参照してみてください。


作成したら、以下の定義のコメントを外して有効にしましょう

#define USE_DB_POSTGRES

#define USE_DB_ORACLE




【ヘッダとソース分解版はこちら】

コピーするファイルの数が多いけど、頑張る!と言う方は、こちらを参照ください。

 ヘッダとソース分解版のコード




参照:

・PostgresSQLのデータを取得するには?

・MySQLのConnectionクラスを追加するには?
・型を気にせずに使用できるクラスを作るには?
・Boostとは?

・virtualとは?

libpqライブラリのドキュメント